Apply prettier to whole project
This commit is contained in:
parent
647e684469
commit
9a91aaf47c
|
|
@ -1,14 +1,15 @@
|
||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"@babel/preset-typescript",
|
"@babel/preset-typescript",
|
||||||
["@babel/preset-env", {
|
[
|
||||||
"useBuiltIns": false,
|
"@babel/preset-env",
|
||||||
"targets": {
|
{
|
||||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
"useBuiltIns": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}]
|
]
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": ["@babel/plugin-transform-runtime"]
|
||||||
"@babel/plugin-transform-runtime"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ module.exports = {
|
||||||
browser: true,
|
browser: true,
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
process: "readonly"
|
process: 'readonly',
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||||
|
|
@ -21,69 +21,77 @@ module.exports = {
|
||||||
'plugin:@typescript-eslint/eslint-recommended',
|
'plugin:@typescript-eslint/eslint-recommended',
|
||||||
],
|
],
|
||||||
// required to lint *.vue files
|
// required to lint *.vue files
|
||||||
plugins: [
|
plugins: ['vue', '@typescript-eslint'],
|
||||||
'vue',
|
overrides: [
|
||||||
'@typescript-eslint'
|
{
|
||||||
|
files: ['*.ts', '*.tsx'],
|
||||||
|
rules: {
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
overrides: [{
|
|
||||||
files: ['*.ts','*.tsx'],
|
|
||||||
rules: {
|
|
||||||
'no-unused-vars': 'off'
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
// add your custom rules here
|
// add your custom rules here
|
||||||
rules: {
|
rules: {
|
||||||
// allow async-await
|
// allow async-await
|
||||||
'generator-star-spacing': 'off',
|
'generator-star-spacing': 'off',
|
||||||
// allow debugger during development
|
// allow debugger during development
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||||
'indent': 'off',
|
indent: 'off',
|
||||||
'semi': ['error', 'always'],
|
semi: ['error', 'always'],
|
||||||
'space-before-function-paren': 'off',
|
'space-before-function-paren': 'off',
|
||||||
'comma-dangle': 'off',
|
'comma-dangle': 'off',
|
||||||
|
|
||||||
// vue rules
|
// vue rules
|
||||||
'vue/require-prop-types': 'off', //todo: should we do this?
|
'vue/require-prop-types': 'off', //todo: should we do this?
|
||||||
'vue/require-default-prop': 'off', //todo: should we do this?
|
'vue/require-default-prop': 'off', //todo: should we do this?
|
||||||
'vue/attributes-order': ['error', {
|
'vue/attributes-order': [
|
||||||
'order': [
|
'error',
|
||||||
'OTHER_ATTR',
|
{
|
||||||
'DEFINITION',
|
order: [
|
||||||
'LIST_RENDERING',
|
'OTHER_ATTR',
|
||||||
'CONDITIONALS',
|
'DEFINITION',
|
||||||
'RENDER_MODIFIERS',
|
'LIST_RENDERING',
|
||||||
'GLOBAL',
|
'CONDITIONALS',
|
||||||
'UNIQUE',
|
'RENDER_MODIFIERS',
|
||||||
'TWO_WAY_BINDING',
|
'GLOBAL',
|
||||||
'OTHER_DIRECTIVES',
|
'UNIQUE',
|
||||||
'EVENTS',
|
'TWO_WAY_BINDING',
|
||||||
'CONTENT'
|
'OTHER_DIRECTIVES',
|
||||||
]
|
'EVENTS',
|
||||||
}],
|
'CONTENT',
|
||||||
"vue/multi-word-component-names": ["off", {
|
],
|
||||||
"ignores": []
|
},
|
||||||
}],
|
],
|
||||||
'vue/order-in-components': ['error', {
|
'vue/multi-word-component-names': [
|
||||||
'order': [
|
'off',
|
||||||
'el',
|
{
|
||||||
'name',
|
ignores: [],
|
||||||
'parent',
|
},
|
||||||
'functional',
|
],
|
||||||
['delimiters', 'comments'],
|
'vue/order-in-components': [
|
||||||
['props', 'propsData'],
|
'error',
|
||||||
'mixins',
|
{
|
||||||
['components', 'directives', 'filters'],
|
order: [
|
||||||
'data',
|
'el',
|
||||||
'extends',
|
'name',
|
||||||
'inheritAttrs',
|
'parent',
|
||||||
'model',
|
'functional',
|
||||||
'computed',
|
['delimiters', 'comments'],
|
||||||
'watch',
|
['props', 'propsData'],
|
||||||
'LIFECYCLE_HOOKS',
|
'mixins',
|
||||||
'methods',
|
['components', 'directives', 'filters'],
|
||||||
['template', 'render'],
|
'data',
|
||||||
'renderError'
|
'extends',
|
||||||
]
|
'inheritAttrs',
|
||||||
}]
|
'model',
|
||||||
}
|
'computed',
|
||||||
|
'watch',
|
||||||
|
'LIFECYCLE_HOOKS',
|
||||||
|
'methods',
|
||||||
|
['template', 'render'],
|
||||||
|
'renderError',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"plugins": {
|
plugins: {
|
||||||
"postcss-import": {},
|
'postcss-import': {},
|
||||||
"postcss-url": {},
|
'postcss-url': {},
|
||||||
// to edit target browsers: use "browserslist" field in package.json
|
// to edit target browsers: use "browserslist" field in package.json
|
||||||
"autoprefixer": {}
|
autoprefixer: {},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,45 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
require('./check-versions')()
|
require('./check-versions')();
|
||||||
|
|
||||||
process.env.NODE_ENV = 'production'
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
const ora = require('ora')
|
const ora = require('ora');
|
||||||
const rm = require('rimraf')
|
const rm = require('rimraf');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const chalk = require('chalk')
|
const chalk = require('chalk');
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack');
|
||||||
const config = require('../config')
|
const config = require('../config');
|
||||||
const webpackConfig = require('./webpack.prod.conf')
|
const webpackConfig = require('./webpack.prod.conf');
|
||||||
|
|
||||||
const spinner = ora('building for production...')
|
const spinner = ora('building for production...');
|
||||||
spinner.start()
|
spinner.start();
|
||||||
|
|
||||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), (err) => {
|
||||||
if (err) throw err
|
if (err) throw err;
|
||||||
webpack(webpackConfig, (err, stats) => {
|
webpack(webpackConfig, (err, stats) => {
|
||||||
spinner.succeed()
|
spinner.succeed();
|
||||||
if (err) throw err
|
if (err) throw err;
|
||||||
process.stdout.write(stats.toString({
|
process.stdout.write(
|
||||||
colors: true,
|
stats.toString({
|
||||||
modules: false,
|
colors: true,
|
||||||
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
|
modules: false,
|
||||||
chunks: false,
|
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
|
||||||
chunkModules: false
|
chunks: false,
|
||||||
}) + '\n\n')
|
chunkModules: false,
|
||||||
|
}) + '\n\n'
|
||||||
|
);
|
||||||
|
|
||||||
if (stats.hasErrors()) {
|
if (stats.hasErrors()) {
|
||||||
console.log(chalk.red(' Build failed with errors.\n'))
|
console.log(chalk.red(' Build failed with errors.\n'));
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(chalk.cyan(' Build complete.\n'))
|
console.log(chalk.cyan(' Build complete.\n'));
|
||||||
console.log(chalk.yellow(
|
console.log(
|
||||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
chalk.yellow(
|
||||||
' Opening index.html over file:// won\'t work.\n'
|
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||||
))
|
" Opening index.html over file:// won't work.\n"
|
||||||
})
|
)
|
||||||
})
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,53 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
const chalk = require('chalk')
|
const chalk = require('chalk');
|
||||||
const semver = require('semver')
|
const semver = require('semver');
|
||||||
const packageConfig = require('../package.json')
|
const packageConfig = require('../package.json');
|
||||||
const shell = require('shelljs')
|
const shell = require('shelljs');
|
||||||
|
|
||||||
function exec (cmd) {
|
function exec(cmd) {
|
||||||
return require('child_process').execSync(cmd).toString().trim()
|
return require('child_process').execSync(cmd).toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const versionRequirements = [
|
const versionRequirements = [
|
||||||
{
|
{
|
||||||
name: 'node',
|
name: 'node',
|
||||||
currentVersion: semver.clean(process.version),
|
currentVersion: semver.clean(process.version),
|
||||||
versionRequirement: packageConfig.engines.node
|
versionRequirement: packageConfig.engines.node,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
if (shell.which('npm')) {
|
if (shell.which('npm')) {
|
||||||
versionRequirements.push({
|
versionRequirements.push({
|
||||||
name: 'npm',
|
name: 'npm',
|
||||||
currentVersion: exec('npm --version'),
|
currentVersion: exec('npm --version'),
|
||||||
versionRequirement: packageConfig.engines.npm
|
versionRequirement: packageConfig.engines.npm,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
const warnings = []
|
const warnings = [];
|
||||||
|
|
||||||
for (let i = 0; i < versionRequirements.length; i++) {
|
for (let i = 0; i < versionRequirements.length; i++) {
|
||||||
const mod = versionRequirements[i]
|
const mod = versionRequirements[i];
|
||||||
|
|
||||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||||
warnings.push(mod.name + ': ' +
|
warnings.push(
|
||||||
chalk.red(mod.currentVersion) + ' should be ' +
|
mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement)
|
||||||
chalk.green(mod.versionRequirement)
|
);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (warnings.length) {
|
if (warnings.length) {
|
||||||
console.log('')
|
console.log('');
|
||||||
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
console.log(chalk.yellow('To use this template, you must update following to modules:'));
|
||||||
console.log()
|
console.log();
|
||||||
|
|
||||||
for (let i = 0; i < warnings.length; i++) {
|
for (let i = 0; i < warnings.length; i++) {
|
||||||
const warning = warnings[i]
|
const warning = warnings[i];
|
||||||
console.log(' ' + warning)
|
console.log(' ' + warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log()
|
console.log();
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const config = require('../config')
|
const config = require('../config');
|
||||||
const packageConfig = require('../package.json')
|
const packageConfig = require('../package.json');
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV !== 'production';
|
const isDev = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
const assetsPath = (_path) => {
|
const assetsPath = (_path) => {
|
||||||
const assetsSubDirectory = isDev
|
const assetsSubDirectory = isDev ? config.dev.assetsSubDirectory : config.build.assetsSubDirectory;
|
||||||
? config.dev.assetsSubDirectory
|
|
||||||
: config.build.assetsSubDirectory
|
|
||||||
|
|
||||||
return path.posix.join(assetsSubDirectory, _path)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return path.posix.join(assetsSubDirectory, _path);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
isDev,
|
isDev,
|
||||||
assetsPath
|
assetsPath,
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ const path = require('path');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
|
||||||
const {VueLoaderPlugin} = require('vue-loader');
|
const { VueLoaderPlugin } = require('vue-loader');
|
||||||
const ESLintPlugin = require('eslint-webpack-plugin');
|
const ESLintPlugin = require('eslint-webpack-plugin');
|
||||||
|
|
||||||
const {isDev, assetsPath} = require('./utils');
|
const { isDev, assetsPath } = require('./utils');
|
||||||
|
|
||||||
function resolve(dir) {
|
function resolve(dir) {
|
||||||
return path.join(__dirname, '..', dir);
|
return path.join(__dirname, '..', dir);
|
||||||
|
|
@ -15,7 +15,7 @@ function resolve(dir) {
|
||||||
const eslintOptions = {
|
const eslintOptions = {
|
||||||
formatter: require('eslint-formatter-friendly'),
|
formatter: require('eslint-formatter-friendly'),
|
||||||
emitWarning: !config.dev.showEslintErrorsInOverlay,
|
emitWarning: !config.dev.showEslintErrorsInOverlay,
|
||||||
extensions: ['js', 'ts', 'vue']
|
extensions: ['js', 'ts', 'vue'],
|
||||||
};
|
};
|
||||||
|
|
||||||
//todo: mini-css-extract-plugin? upgrade to webpack 4, then use this
|
//todo: mini-css-extract-plugin? upgrade to webpack 4, then use this
|
||||||
|
|
@ -29,9 +29,7 @@ module.exports = {
|
||||||
output: {
|
output: {
|
||||||
path: config.build.assetsRoot,
|
path: config.build.assetsRoot,
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
publicPath: isDev
|
publicPath: isDev ? config.dev.assetsPublicPath : config.build.assetsPublicPath,
|
||||||
? config.dev.assetsPublicPath
|
|
||||||
: config.build.assetsPublicPath,
|
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
splitChunks: {
|
splitChunks: {
|
||||||
|
|
@ -131,10 +129,7 @@ module.exports = {
|
||||||
// styleRule(true), // sass rule
|
// styleRule(true), // sass rule
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [new VueLoaderPlugin(), new ESLintPlugin(eslintOptions)],
|
||||||
new VueLoaderPlugin(),
|
|
||||||
new ESLintPlugin(eslintOptions),
|
|
||||||
],
|
|
||||||
|
|
||||||
// node: {
|
// node: {
|
||||||
// // prevent webpack from injecting useless setImmediate polyfill because Vue
|
// // prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||||
const portfinder = require('portfinder');
|
const portfinder = require('portfinder');
|
||||||
const {merge} = require('webpack-merge');
|
const { merge } = require('webpack-merge');
|
||||||
|
|
||||||
const HOST = process.env.HOST;
|
const HOST = process.env.HOST;
|
||||||
const PORT = process.env.PORT && Number(process.env.PORT);
|
const PORT = process.env.PORT && Number(process.env.PORT);
|
||||||
|
|
@ -21,15 +21,12 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
devServer: {
|
devServer: {
|
||||||
client: {
|
client: {
|
||||||
logging: 'warn',
|
logging: 'warn',
|
||||||
overlay: config.dev.errorOverlay ? {errors: true, warnings: false} : false,
|
overlay: config.dev.errorOverlay ? { errors: true, warnings: false } : false,
|
||||||
progress: true,
|
progress: true,
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
historyApiFallback: {
|
historyApiFallback: {
|
||||||
rewrites: [
|
rewrites: [{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }],
|
||||||
{from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html')},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
hot: true,
|
hot: true,
|
||||||
compress: true,
|
compress: true,
|
||||||
|
|
@ -66,8 +63,8 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
new BundleAnalyzerPlugin({
|
new BundleAnalyzerPlugin({
|
||||||
analyzerMode: 'disabled' // do nothing by default, but be able to generate stats with --profile
|
analyzerMode: 'disabled', // do nothing by default, but be able to generate stats with --profile
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ const path = require('path');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const {merge} = require('webpack-merge');
|
const { merge } = require('webpack-merge');
|
||||||
const baseWebpackConfig = require('./webpack.base.conf');
|
const baseWebpackConfig = require('./webpack.base.conf');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||||
|
|
||||||
const env = require('../config/prod.env');
|
const env = require('../config/prod.env');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
|
@ -21,9 +21,7 @@ const webpackConfig = merge(baseWebpackConfig, {
|
||||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
|
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
minimizer: [
|
minimizer: [new CssMinimizerPlugin()],
|
||||||
new CssMinimizerPlugin()
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||||
|
|
@ -44,7 +42,8 @@ const webpackConfig = merge(baseWebpackConfig, {
|
||||||
filename: config.build.index,
|
filename: config.build.index,
|
||||||
template: 'index.html',
|
template: 'index.html',
|
||||||
...require('../config/prod.env'),
|
...require('../config/prod.env'),
|
||||||
minify: { // defaults from https://github.com/jantimon/html-webpack-plugin#minification
|
minify: {
|
||||||
|
// defaults from https://github.com/jantimon/html-webpack-plugin#minification
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
keepClosingSlash: true,
|
keepClosingSlash: true,
|
||||||
removeComments: true,
|
removeComments: true,
|
||||||
|
|
@ -112,14 +111,10 @@ if (config.build.productionGzip) {
|
||||||
new CompressionWebpackPlugin({
|
new CompressionWebpackPlugin({
|
||||||
asset: '[path].gz[query]',
|
asset: '[path].gz[query]',
|
||||||
algorithm: 'gzip',
|
algorithm: 'gzip',
|
||||||
test: new RegExp(
|
test: new RegExp('\\.(' + config.build.productionGzipExtensions.join('|') + ')$'),
|
||||||
'\\.(' +
|
|
||||||
config.build.productionGzipExtensions.join('|') +
|
|
||||||
')$',
|
|
||||||
),
|
|
||||||
threshold: 10240,
|
threshold: 10240,
|
||||||
minRatio: 0.8,
|
minRatio: 0.8,
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
const {merge} = require('webpack-merge')
|
const { merge } = require('webpack-merge');
|
||||||
const prodEnv = require('./prod.env')
|
const prodEnv = require('./prod.env');
|
||||||
|
|
||||||
module.exports = merge(prodEnv, {
|
module.exports = merge(prodEnv, {
|
||||||
NODE_ENV: '"development"',
|
NODE_ENV: '"development"',
|
||||||
VUE_APP_ENABLE_SPELLCHECK: 'true'
|
VUE_APP_ENABLE_SPELLCHECK: 'true',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
// Template version: 1.3.1
|
// Template version: 1.3.1
|
||||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||||
|
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
dev: {
|
dev: {
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
assetsSubDirectory: 'static',
|
assetsSubDirectory: 'static',
|
||||||
assetsPublicPath: '/',
|
assetsPublicPath: '/',
|
||||||
|
|
@ -41,7 +40,7 @@ module.exports = {
|
||||||
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||||
cacheBusting: true,
|
cacheBusting: true,
|
||||||
|
|
||||||
cssSourceMap: true
|
cssSourceMap: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
|
|
@ -71,6 +70,6 @@ module.exports = {
|
||||||
// View the bundle analyzer report after build finishes:
|
// View the bundle analyzer report after build finishes:
|
||||||
// `npm run build --report`
|
// `npm run build --report`
|
||||||
// Set to `true` or `false` to always turn it on or off
|
// Set to `true` or `false` to always turn it on or off
|
||||||
bundleAnalyzerReport: process.env.npm_config_report
|
bundleAnalyzerReport: process.env.npm_config_report,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/*
|
/*
|
||||||
* ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes
|
* ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes
|
||||||
* around strings
|
* around strings
|
||||||
*/
|
*/
|
||||||
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -12,6 +12,6 @@ module.exports = {
|
||||||
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
||||||
VUE_APP_FAVICON_32: 'https://skillbox-my-detailhandel-dha-prod.s3.eu-central-1.amazonaws.com/myDHA-favicon.png',
|
VUE_APP_FAVICON_32: 'https://skillbox-my-detailhandel-dha-prod.s3.eu-central-1.amazonaws.com/myDHA-favicon.png',
|
||||||
VUE_APP_FAVICON_16: 'https://skillbox-my-detailhandel-dha-prod.s3.eu-central-1.amazonaws.com/myDHA-favicon.png',
|
VUE_APP_FAVICON_16: 'https://skillbox-my-detailhandel-dha-prod.s3.eu-central-1.amazonaws.com/myDHA-favicon.png',
|
||||||
VUE_APP_TITLE: 'myDHA'
|
VUE_APP_TITLE: 'myDHA',
|
||||||
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/*
|
/*
|
||||||
* ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes
|
* ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes
|
||||||
* around strings
|
* around strings
|
||||||
*/
|
*/
|
||||||
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -12,6 +12,6 @@ module.exports = {
|
||||||
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
||||||
VUE_APP_FAVICON_32: 'https://skillbox-my-detailhandel-dhf-prod.s3.eu-central-1.amazonaws.com/myDHF-favicon.png',
|
VUE_APP_FAVICON_32: 'https://skillbox-my-detailhandel-dhf-prod.s3.eu-central-1.amazonaws.com/myDHF-favicon.png',
|
||||||
VUE_APP_FAVICON_16: 'https://skillbox-my-detailhandel-dhf-prod.s3.eu-central-1.amazonaws.com/myDHF-favicon.png',
|
VUE_APP_FAVICON_16: 'https://skillbox-my-detailhandel-dhf-prod.s3.eu-central-1.amazonaws.com/myDHF-favicon.png',
|
||||||
VUE_APP_TITLE: 'myDHF'
|
VUE_APP_TITLE: 'myDHF',
|
||||||
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/*
|
/*
|
||||||
* ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes
|
* ENV variables used in JS code need to be stringyfied, as they will be replaced in the code, and JS needs quotes
|
||||||
* around strings
|
* around strings
|
||||||
*/
|
*/
|
||||||
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -12,6 +12,6 @@ module.exports = {
|
||||||
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
||||||
VUE_APP_FAVICON_32: 'https://skillbox-my-kv-prod.s3-eu-west-1.amazonaws.com/mykv-favicon.png',
|
VUE_APP_FAVICON_32: 'https://skillbox-my-kv-prod.s3-eu-west-1.amazonaws.com/mykv-favicon.png',
|
||||||
VUE_APP_FAVICON_16: 'https://skillbox-my-kv-prod.s3-eu-west-1.amazonaws.com/mykv-favicon.png',
|
VUE_APP_FAVICON_16: 'https://skillbox-my-kv-prod.s3-eu-west-1.amazonaws.com/mykv-favicon.png',
|
||||||
VUE_APP_TITLE: 'myKV'
|
VUE_APP_TITLE: 'myKV',
|
||||||
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
const { merge } = require('webpack-merge')
|
const { merge } = require('webpack-merge');
|
||||||
|
|
||||||
const values = {
|
const values = {
|
||||||
NODE_ENV: '"production"',
|
NODE_ENV: '"production"',
|
||||||
|
|
@ -9,10 +9,10 @@ const values = {
|
||||||
LOGOUT_REDIRECT_URL: JSON.stringify(process.env.LOGOUT_REDIRECT_URL),
|
LOGOUT_REDIRECT_URL: JSON.stringify(process.env.LOGOUT_REDIRECT_URL),
|
||||||
VUE_APP_FLAVOR: JSON.stringify(process.env.APP_FLAVOR),
|
VUE_APP_FLAVOR: JSON.stringify(process.env.APP_FLAVOR),
|
||||||
/*
|
/*
|
||||||
* ENV variables used in JS code need to be stringyfied, as they will be replaced (in place) in the code,
|
* ENV variables used in JS code need to be stringyfied, as they will be replaced (in place) in the code,
|
||||||
* and JS needs quotes around strings
|
* and JS needs quotes around strings
|
||||||
* see https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code
|
* see https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code
|
||||||
*/
|
*/
|
||||||
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
VUE_APP_ENABLE_SPELLCHECK: !!process.env.TASKBASE_BASEURL,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -21,9 +21,9 @@ const values = {
|
||||||
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
// vvvv HTML PROPERTIES FROM HERE, NOT STRINGIFIED vvvv
|
||||||
VUE_APP_FAVICON_32: '/static/favicon-32x32.png',
|
VUE_APP_FAVICON_32: '/static/favicon-32x32.png',
|
||||||
VUE_APP_FAVICON_16: '/static/favicon-16x16.png',
|
VUE_APP_FAVICON_16: '/static/favicon-16x16.png',
|
||||||
VUE_APP_TITLE: 'mySkillbox'
|
VUE_APP_TITLE: 'mySkillbox',
|
||||||
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
// ^^^^ HTML PROPERTIES TO HERE, NOT STRINGIFIED ^^^^
|
||||||
}
|
};
|
||||||
|
|
||||||
switch (process.env.APP_FLAVOR) {
|
switch (process.env.APP_FLAVOR) {
|
||||||
case 'my-kv':
|
case 'my-kv':
|
||||||
|
|
@ -39,4 +39,3 @@ switch (process.env.APP_FLAVOR) {
|
||||||
// we are on the skillbox APP_FLAVOR
|
// we are on the skillbox APP_FLAVOR
|
||||||
module.exports = values;
|
module.exports = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
import {defineConfig} from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
import {readFileSync} from "fs";
|
import { readFileSync } from 'fs';
|
||||||
import {resolve} from "path";
|
import { resolve } from 'path';
|
||||||
export default defineConfig( {
|
export default defineConfig({
|
||||||
e2e: {
|
e2e: {
|
||||||
"baseUrl": "http://localhost:8000",
|
baseUrl: 'http://localhost:8000',
|
||||||
specPattern: 'cypress/e2e/e2e/**/*.{spec,cy}.{js,ts}',
|
specPattern: 'cypress/e2e/e2e/**/*.{spec,cy}.{js,ts}',
|
||||||
supportFile: 'cypress/support/e2e.ts',
|
supportFile: 'cypress/support/e2e.ts',
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
on('task', {
|
on('task', {
|
||||||
getSchema() {
|
getSchema() {
|
||||||
return readFileSync(
|
return readFileSync(resolve(__dirname, '../server/schema.graphql'), 'utf8');
|
||||||
resolve(__dirname, '../server/schema.graphql'),
|
},
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"videoUploadOnPasses": false,
|
videoUploadOnPasses: false,
|
||||||
"reporter": "junit",
|
reporter: 'junit',
|
||||||
"reporterOptions": {
|
reporterOptions: {
|
||||||
"mochaFile": "cypress/test-reports/e2e/cypress-results-[hash].xml",
|
mochaFile: 'cypress/test-reports/e2e/cypress-results-[hash].xml',
|
||||||
"toConsole": true
|
toConsole: true,
|
||||||
},
|
},
|
||||||
"projectId": "msk-ee",
|
projectId: 'msk-ee',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,29 @@
|
||||||
import {defineConfig} from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
import {readFileSync} from "fs";
|
import { readFileSync } from 'fs';
|
||||||
import {resolve} from "path";
|
import { resolve } from 'path';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
e2e: {
|
e2e: {
|
||||||
baseUrl: "http://localhost:8080",
|
baseUrl: 'http://localhost:8080',
|
||||||
specPattern: 'cypress/e2e/frontend/**/*.{cy,spec}.{js,ts}',
|
specPattern: 'cypress/e2e/frontend/**/*.{cy,spec}.{js,ts}',
|
||||||
supportFile: 'cypress/support/e2e.ts',
|
supportFile: 'cypress/support/e2e.ts',
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
on('task', {
|
on('task', {
|
||||||
getSchema() {
|
getSchema() {
|
||||||
return readFileSync(
|
return readFileSync(resolve(__dirname, '../server/schema.graphql'), 'utf8');
|
||||||
resolve(__dirname, '../server/schema.graphql'),
|
},
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
videoUploadOnPasses: false,
|
videoUploadOnPasses: false,
|
||||||
reporter: "junit",
|
reporter: 'junit',
|
||||||
reporterOptions: {
|
reporterOptions: {
|
||||||
mochaFile: "cypress/test-reports/frontend/cypress-results-[hash].xml",
|
mochaFile: 'cypress/test-reports/frontend/cypress-results-[hash].xml',
|
||||||
toConsole: true
|
toConsole: true,
|
||||||
},
|
},
|
||||||
"projectId": "msk-fe",
|
projectId: 'msk-fe',
|
||||||
retries: {
|
retries: {
|
||||||
runMode: 3
|
runMode: 3,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,43 +1,41 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
|
||||||
<title><%= htmlWebpackPlugin.options.VUE_APP_TITLE %></title>
|
<title><%= htmlWebpackPlugin.options.VUE_APP_TITLE %></title>
|
||||||
|
|
||||||
<link href='https://fonts.googleapis.com/css?family=Material+Icons' rel="stylesheet" type="text/css">
|
<link href="https://fonts.googleapis.com/css?family=Material+Icons" rel="stylesheet" type="text/css" />
|
||||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,800" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,800" rel="stylesheet" />
|
||||||
<link href="https://use.typekit.net/tck7ptw.css" rel="stylesheet">
|
<link href="https://use.typekit.net/tck7ptw.css" rel="stylesheet" />
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png" />
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="<%- htmlWebpackPlugin.options.VUE_APP_FAVICON_32 %>">
|
<link rel="icon" type="image/png" sizes="32x32" href="<%- htmlWebpackPlugin.options.VUE_APP_FAVICON_32 %>" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="<%- htmlWebpackPlugin.options.VUE_APP_FAVICON_16 %>">
|
<link rel="icon" type="image/png" sizes="16x16" href="<%- htmlWebpackPlugin.options.VUE_APP_FAVICON_16 %>" />
|
||||||
<link rel="manifest" href="/static/site.webmanifest">
|
<link rel="manifest" href="/static/site.webmanifest" />
|
||||||
<link rel="mask-icon" href="/static/safari-pinned-tab.svg" color="#5bbad5">
|
<link rel="mask-icon" href="/static/safari-pinned-tab.svg" color="#5bbad5" />
|
||||||
<meta name="msapplication-TileColor" content="#da532c">
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.UPLOADCARE_PUBLIC_KEY = '78212ff39934a59775ac';
|
window.UPLOADCARE_PUBLIC_KEY = '78212ff39934a59775ac';
|
||||||
window.UPLOADCARE_LOCALE = 'de';
|
window.UPLOADCARE_LOCALE = 'de';
|
||||||
window.UPLOADCARE_LOCALE_TRANSLATIONS = {
|
window.UPLOADCARE_LOCALE_TRANSLATIONS = {
|
||||||
dialog: {
|
dialog: {
|
||||||
tabs: {
|
tabs: {
|
||||||
file: {
|
file: {
|
||||||
drag: 'Ziehen Sie ein Bild hier hinein',
|
drag: 'Ziehen Sie ein Bild hier hinein',
|
||||||
button: 'Wählen Sie ein lokales Bild',
|
button: 'Wählen Sie ein lokales Bild',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
</head>
|
||||||
</head>
|
<body>
|
||||||
<body>
|
<div id="app">
|
||||||
<div id="app">
|
<div class="center"></div>
|
||||||
<div class="center">
|
</div>
|
||||||
</div>
|
<!-- built files will be auto injected -->
|
||||||
</div>
|
</body>
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
moduleFileExtensions: [
|
moduleFileExtensions: ['js', 'jsx', 'ts', 'json', 'vue'],
|
||||||
'js',
|
|
||||||
'jsx',
|
|
||||||
'ts',
|
|
||||||
'json',
|
|
||||||
'vue',
|
|
||||||
],
|
|
||||||
transform: {
|
transform: {
|
||||||
'\\.(gql|graphql)$': 'jest-transform-graphql',
|
'\\.(gql|graphql)$': 'jest-transform-graphql',
|
||||||
'^.+\\.js$': 'babel-jest',
|
'^.+\\.js$': 'babel-jest',
|
||||||
|
|
@ -13,27 +7,15 @@ module.exports = {
|
||||||
'^.+\\.vue$': '@vue/vue2-jest',
|
'^.+\\.vue$': '@vue/vue2-jest',
|
||||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
|
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
|
||||||
},
|
},
|
||||||
modulePaths: [
|
modulePaths: ['<rootDir>/src', '<rootDir>/node_modules'],
|
||||||
'<rootDir>/src',
|
transformIgnorePatterns: ['/node_modules/'],
|
||||||
'<rootDir>/node_modules',
|
|
||||||
],
|
|
||||||
transformIgnorePatterns: [
|
|
||||||
'/node_modules/',
|
|
||||||
],
|
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'^@/(.*)$': '<rootDir>/src/$1',
|
'^@/(.*)$': '<rootDir>/src/$1',
|
||||||
'^gql/(.*)$': '<rootDir>/src/graphql/gql/$1',
|
'^gql/(.*)$': '<rootDir>/src/graphql/gql/$1',
|
||||||
},
|
},
|
||||||
snapshotSerializers: [
|
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
|
||||||
'<rootDir>/node_modules/jest-serializer-vue',
|
|
||||||
],
|
|
||||||
testEnvironment: 'jsdom',
|
testEnvironment: 'jsdom',
|
||||||
testMatch: [
|
testMatch: ['**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'],
|
||||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)',
|
|
||||||
],
|
|
||||||
testURL: 'http://localhost/',
|
testURL: 'http://localhost/',
|
||||||
watchPlugins: [
|
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
|
||||||
'jest-watch-typeahead/filename',
|
|
||||||
'jest-watch-typeahead/testname',
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,26 @@
|
||||||
const {readFileSync} = require('fs');
|
const { readFileSync } = require('fs');
|
||||||
const {resolve} = require('path');
|
const { resolve } = require('path');
|
||||||
const { addMocksToSchema} = require('@graphql-tools/mock');
|
const { addMocksToSchema } = require('@graphql-tools/mock');
|
||||||
const { makeExecutableSchema } = require('@graphql-tools/schema');
|
const { makeExecutableSchema } = require('@graphql-tools/schema');
|
||||||
const { graphql } = require('graphql');
|
const { graphql } = require('graphql');
|
||||||
|
|
||||||
const schemaString = readFileSync(
|
const schemaString = readFileSync(resolve(__dirname, '../server/schema.graphql'), 'utf8');
|
||||||
resolve(__dirname,'../server/schema.graphql'),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Make a GraphQL schema with no resolvers
|
// Make a GraphQL schema with no resolvers
|
||||||
const schema = makeExecutableSchema({ typeDefs: schemaString })
|
const schema = makeExecutableSchema({ typeDefs: schemaString });
|
||||||
|
|
||||||
// Create a new schema with mocks
|
// Create a new schema with mocks
|
||||||
const schemaWithMocks = addMocksToSchema({ schema })
|
const schemaWithMocks = addMocksToSchema({ schema });
|
||||||
|
|
||||||
const query = /* GraphQL */ `
|
const query = /* GraphQL */ `
|
||||||
query MeQuery {
|
query MeQuery {
|
||||||
me {
|
me {
|
||||||
firstName
|
firstName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
graphql({
|
graphql({
|
||||||
schema: schemaWithMocks,
|
schema: schemaWithMocks,
|
||||||
source: query,
|
source: query,
|
||||||
}).then(result => console.log('Got result', result))
|
}).then((result) => console.log('Got result', result));
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
declare module '*.graphql' {
|
declare module '*.graphql' {
|
||||||
import {DocumentNode} from "graphql";
|
import { DocumentNode } from 'graphql';
|
||||||
const Schema: DocumentNode;
|
const Schema: DocumentNode;
|
||||||
|
|
||||||
export = Schema;
|
export = Schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.gql' {
|
declare module '*.gql' {
|
||||||
import {DocumentNode} from "graphql";
|
import { DocumentNode } from 'graphql';
|
||||||
const content: DocumentNode;
|
const content: DocumentNode;
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export interface ContentBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionOptions {
|
export interface ActionOptions {
|
||||||
up?: boolean,
|
up?: boolean;
|
||||||
down?: boolean,
|
down?: boolean;
|
||||||
extended?: boolean
|
extended?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,109 +1,107 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="{ 'no-scroll': showModal || showMobileNavigation }" class="app" id="app">
|
||||||
:class="{'no-scroll': showModal || showMobileNavigation}"
|
|
||||||
class="app"
|
|
||||||
id="app"
|
|
||||||
>
|
|
||||||
<read-only-banner />
|
<read-only-banner />
|
||||||
<scroll-up />
|
<scroll-up />
|
||||||
<component
|
<component :is="showModalDeprecated" v-if="showModalDeprecated" />
|
||||||
:is="showModalDeprecated"
|
<component :is="showModal" v-if="showModal" />
|
||||||
v-if="showModalDeprecated"
|
|
||||||
/>
|
|
||||||
<component
|
|
||||||
:is="showModal"
|
|
||||||
v-if="showModal"
|
|
||||||
/>
|
|
||||||
<component :is="layout" />
|
<component :is="layout" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters} from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import ScrollUp from '@/components/ScrollUp';
|
import ScrollUp from '@/components/ScrollUp';
|
||||||
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
|
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
|
||||||
|
|
||||||
import modals from '@/components/modals';
|
import modals from '@/components/modals';
|
||||||
|
|
||||||
const NewContentBlockWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/content-block-form/NewContentBlockWizard');
|
const NewContentBlockWizard = () =>
|
||||||
const EditContentBlockWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/content-block-form/EditContentBlockWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/NewContentBlockWizard');
|
||||||
const EditRoomEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/rooms/room-entries/EditRoomEntryWizard');
|
const EditContentBlockWizard = () =>
|
||||||
const NewProjectEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/portfolio/NewProjectEntryWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/EditContentBlockWizard');
|
||||||
const EditProjectEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/portfolio/EditProjectEntryWizard');
|
const EditRoomEntryWizard = () =>
|
||||||
const NewObjectiveWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/objective-groups/NewObjectiveWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/rooms/room-entries/EditRoomEntryWizard');
|
||||||
const NewNoteWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/notes/NewNoteWizard');
|
const NewProjectEntryWizard = () =>
|
||||||
const EditNoteWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/notes/EditNoteWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/portfolio/NewProjectEntryWizard');
|
||||||
const EditClassNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/school-class/EditClassNameWizard');
|
const EditProjectEntryWizard = () =>
|
||||||
const EditTeamNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/profile/EditTeamNameWizard');
|
import(/* webpackChunkName: "content-forms" */ '@/components/portfolio/EditProjectEntryWizard');
|
||||||
const EditSnapshotTitleWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/snapshots/EditSnapshotTitleWizard');
|
const NewObjectiveWizard = () =>
|
||||||
const DefaultLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/DefaultLayout');
|
import(/* webpackChunkName: "content-forms" */ '@/components/objective-groups/NewObjectiveWizard');
|
||||||
const SimpleLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SimpleLayout');
|
const NewNoteWizard = () => import(/* webpackChunkName: "content-forms" */ '@/components/notes/NewNoteWizard');
|
||||||
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/FullScreenLayout');
|
const EditNoteWizard = () => import(/* webpackChunkName: "content-forms" */ '@/components/notes/EditNoteWizard');
|
||||||
const PublicLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/PublicLayout');
|
const EditClassNameWizard = () =>
|
||||||
const BlankLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/BlankLayout');
|
import(/* webpackChunkName: "content-forms" */ '@/components/school-class/EditClassNameWizard');
|
||||||
const SplitLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SplitLayout');
|
const EditTeamNameWizard = () =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/profile/EditTeamNameWizard');
|
||||||
|
const EditSnapshotTitleWizard = () =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/snapshots/EditSnapshotTitleWizard');
|
||||||
|
const DefaultLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/DefaultLayout');
|
||||||
|
const SimpleLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/SimpleLayout');
|
||||||
|
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/FullScreenLayout');
|
||||||
|
const PublicLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/PublicLayout');
|
||||||
|
const BlankLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/BlankLayout');
|
||||||
|
const SplitLayout = () => import(/* webpackChunkName: "layouts" */ '@/layouts/SplitLayout');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ReadOnlyBanner,
|
ReadOnlyBanner,
|
||||||
ScrollUp,
|
ScrollUp,
|
||||||
DefaultLayout,
|
DefaultLayout,
|
||||||
SimpleLayout,
|
SimpleLayout,
|
||||||
FullScreenLayout,
|
FullScreenLayout,
|
||||||
PublicLayout,
|
PublicLayout,
|
||||||
BlankLayout,
|
BlankLayout,
|
||||||
SplitLayout,
|
SplitLayout,
|
||||||
NewContentBlockWizard,
|
NewContentBlockWizard,
|
||||||
EditContentBlockWizard,
|
EditContentBlockWizard,
|
||||||
EditRoomEntryWizard,
|
EditRoomEntryWizard,
|
||||||
NewProjectEntryWizard,
|
NewProjectEntryWizard,
|
||||||
EditProjectEntryWizard,
|
EditProjectEntryWizard,
|
||||||
NewObjectiveWizard,
|
NewObjectiveWizard,
|
||||||
NewNoteWizard,
|
NewNoteWizard,
|
||||||
EditNoteWizard,
|
EditNoteWizard,
|
||||||
EditClassNameWizard,
|
EditClassNameWizard,
|
||||||
EditTeamNameWizard,
|
EditTeamNameWizard,
|
||||||
EditSnapshotTitleWizard,
|
EditSnapshotTitleWizard,
|
||||||
...modals
|
...modals,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
layout() {
|
||||||
|
return (this.$route.meta.layout || 'default') + '-layout';
|
||||||
},
|
},
|
||||||
|
...mapGetters({
|
||||||
computed: {
|
showModalDeprecated: 'showModal', // don't use this any more todo: remove this
|
||||||
layout() {
|
showMobileNavigation: 'showMobileNavigation',
|
||||||
return (this.$route.meta.layout || 'default') + '-layout';
|
}),
|
||||||
},
|
showModal() {
|
||||||
...mapGetters({
|
return this.$modal.state.component;
|
||||||
showModalDeprecated: 'showModal', // don't use this any more todo: remove this
|
|
||||||
showMobileNavigation: 'showMobileNavigation',
|
|
||||||
}),
|
|
||||||
showModal() {
|
|
||||||
return this.$modal.state.component;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/main.scss";
|
@import '~styles/main.scss';
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
body {
|
body {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app {
|
.app {
|
||||||
/*overflow-y: auto;*/
|
/*overflow-y: auto;*/
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
/*for IE10+*/
|
/*for IE10+*/
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-scroll {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.no-scroll {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,104 +1,98 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="add-content">
|
<div class="add-content">
|
||||||
<a
|
<a class="add-content__button" @click="addContent">
|
||||||
class="add-content__button"
|
|
||||||
@click="addContent"
|
|
||||||
>
|
|
||||||
<add-pointer class="add-content__icon" />
|
<add-pointer class="add-content__icon" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { CREATE_CONTENT_BLOCK_AFTER_PAGE, CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE } from '@/router/module.names';
|
||||||
CREATE_CONTENT_BLOCK_AFTER_PAGE,
|
|
||||||
CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
|
|
||||||
} from '@/router/module.names';
|
|
||||||
|
|
||||||
const AddPointer = () => import(/* webpackChunkName: "icons" */'@/components/icons/AddPointer');
|
const AddPointer = () => import(/* webpackChunkName: "icons" */ '@/components/icons/AddPointer');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
where: {
|
where: {
|
||||||
type: Object,
|
type: Object,
|
||||||
validator(prop) {
|
validator(prop) {
|
||||||
return Object.prototype.hasOwnProperty.call(prop, 'after' )
|
return (
|
||||||
|| Object.prototype.hasOwnProperty.call(prop, 'parent');
|
Object.prototype.hasOwnProperty.call(prop, 'after') || Object.prototype.hasOwnProperty.call(prop, 'parent')
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AddPointer
|
AddPointer,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
parent() {
|
||||||
|
return this.where.parent;
|
||||||
},
|
},
|
||||||
|
after() {
|
||||||
computed: {
|
return this.where.after;
|
||||||
parent() {
|
|
||||||
return this.where.parent;
|
|
||||||
},
|
|
||||||
after() {
|
|
||||||
return this.where.after;
|
|
||||||
},
|
|
||||||
isObjectiveGroup() {
|
|
||||||
return this.parent && this.parent.__typename === 'ObjectiveGroupNode';
|
|
||||||
},
|
|
||||||
slug() {
|
|
||||||
return this.$route.params.slug;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
isObjectiveGroup() {
|
||||||
|
return this.parent && this.parent.__typename === 'ObjectiveGroupNode';
|
||||||
|
},
|
||||||
|
slug() {
|
||||||
|
return this.$route.params.slug;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
methods: {
|
addContent() {
|
||||||
addContent() {
|
if (this.isObjectiveGroup) {
|
||||||
if (this.isObjectiveGroup) {
|
this.$modal.open('new-objective-wizard', { parent: this.parent.id });
|
||||||
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 {
|
} else {
|
||||||
let route;
|
route = {
|
||||||
if (this.after && this.after.id) {
|
name: CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
|
||||||
route = {
|
params: {
|
||||||
name: CREATE_CONTENT_BLOCK_AFTER_PAGE,
|
parent: this.parent.id,
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.add-content {
|
.add-content {
|
||||||
display: none;
|
display: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
@include desktop {
|
@include desktop {
|
||||||
display: flex;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
margin-right: -85px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 40px;
|
||||||
|
fill: $color-silver-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="add-content-element" @click="$emit('add-element', index)">
|
||||||
class="add-content-element"
|
|
||||||
@click="$emit('add-element', index)"
|
|
||||||
>
|
|
||||||
<add-icon class="add-content-element__icon" />
|
<add-icon class="add-content-element__icon" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const AddIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon');
|
const AddIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/AddIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['index'],
|
props: ['index'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AddIcon
|
AddIcon,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.add-content-element {
|
.add-content-element {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-bottom: 2px solid $color-silver-dark;
|
border-bottom: 2px solid $color-silver-dark;
|
||||||
margin-bottom: 21px + 25px;
|
margin-bottom: 21px + 25px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
fill: $color-silver-dark;
|
fill: $color-silver-dark;
|
||||||
margin-bottom: -21px;
|
margin-bottom: -21px;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -11,68 +11,71 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const AddIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon.vue');
|
const AddIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/AddIcon.vue');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
route: {
|
route: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null,
|
||||||
},
|
|
||||||
reverse: { // use reverse colors
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
click: {
|
|
||||||
type: Function,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
reverse: {
|
||||||
|
// use reverse colors
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
click: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AddIcon
|
AddIcon,
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
component() {
|
component() {
|
||||||
// only use the router link if the route prop is provided, otherwise render a normal anchor tag
|
// only use the router link if the route prop is provided, otherwise render a normal anchor tag
|
||||||
return this.route ? 'router-link' : 'a';
|
return this.route ? 'router-link' : 'a';
|
||||||
},
|
|
||||||
properties() {
|
|
||||||
return this.route ? {
|
|
||||||
to: this.route,
|
|
||||||
tag: 'div'
|
|
||||||
} : {};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
properties() {
|
||||||
|
return this.route
|
||||||
|
? {
|
||||||
|
to: this.route,
|
||||||
|
tag: 'div',
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.add-widget {
|
.add-widget {
|
||||||
display: none;
|
display: none;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@include widget-shadow;
|
@include widget-shadow;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
|
||||||
|
|
||||||
&__add {
|
|
||||||
width: 80px;
|
|
||||||
fill: $color-silver-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--reverse {
|
|
||||||
@include widget-shadow-reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--reverse &__add {
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__add {
|
||||||
|
width: 80px;
|
||||||
|
fill: $color-silver-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--reverse {
|
||||||
|
@include widget-shadow-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--reverse &__add {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="assignment-with-submissions">
|
<div class="assignment-with-submissions">
|
||||||
<p
|
<p class="assignment-with-submissions__text" data-cy="assignment-main-text" v-html="assignment.assignment" />
|
||||||
class="assignment-with-submissions__text"
|
|
||||||
data-cy="assignment-main-text"
|
|
||||||
v-html="assignment.assignment"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a class="button button--primary submissions-page__back" @click="$emit('back')"
|
||||||
class="button button--primary submissions-page__back"
|
>Aufgabe im {{ $flavor.textModule }} anzeigen</a
|
||||||
@click="$emit('back')"
|
>
|
||||||
>Aufgabe im {{ $flavor.textModule }} anzeigen</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="assignment-with-submissions__solution" v-if="assignment.solution">
|
||||||
class="assignment-with-submissions__solution"
|
<h4 class="assignment-with-submissions__heading">Lösung</h4>
|
||||||
v-if="assignment.solution"
|
|
||||||
>
|
|
||||||
<h4 class="assignment-with-submissions__heading">
|
|
||||||
Lösung
|
|
||||||
</h4>
|
|
||||||
<p
|
<p
|
||||||
class="assignment-with-submissions__solution-text"
|
class="assignment-with-submissions__solution-text"
|
||||||
data-cy="assignment-solution"
|
data-cy="assignment-solution"
|
||||||
v-html="assignment.solution"
|
v-html="assignment.solution"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p class="assignment-with-submissions__no-submissions" v-if="!assignment.submissions.length">
|
||||||
class="assignment-with-submissions__no-submissions"
|
|
||||||
v-if="!assignment.submissions.length"
|
|
||||||
>
|
|
||||||
Zu diesem Auftrag sind noch keine Ergebnisse vorhanden.
|
Zu diesem Auftrag sind noch keine Ergebnisse vorhanden.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div
|
<div class="assignment-with-submissions__submissions submissions" v-if="assignment.submissions.length">
|
||||||
class="assignment-with-submissions__submissions submissions"
|
|
||||||
v-if="assignment.submissions.length"
|
|
||||||
>
|
|
||||||
<div class="submissions__header student-submission-row submission-header">
|
<div class="submissions__header student-submission-row submission-header">
|
||||||
<p class="submission-header__title">
|
<p class="submission-header__title">Lernende</p>
|
||||||
Lernende
|
<p class="submission-header__title">Ergebnisse</p>
|
||||||
</p>
|
<p class="submission-header__title">Feedback</p>
|
||||||
<p class="submission-header__title">
|
|
||||||
Ergebnisse
|
|
||||||
</p>
|
|
||||||
<p class="submission-header__title">
|
|
||||||
Feedback
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<router-link
|
<router-link
|
||||||
:to="submissionLink(submission)"
|
:to="submissionLink(submission)"
|
||||||
|
|
@ -55,116 +33,110 @@
|
||||||
v-for="submission in submissions"
|
v-for="submission in submissions"
|
||||||
:key="submission.id"
|
:key="submission.id"
|
||||||
>
|
>
|
||||||
<student-submission
|
<student-submission :submission="submission" class="assignment-with-submissions__submission" />
|
||||||
:submission="submission"
|
|
||||||
class="assignment-with-submissions__submission"
|
|
||||||
/>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import StudentSubmission from '@/components/StudentSubmission';
|
import StudentSubmission from '@/components/StudentSubmission';
|
||||||
|
|
||||||
import { meQuery } from '@/graphql/queries';
|
import { meQuery } from '@/graphql/queries';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['assignment'],
|
props: ['assignment'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
StudentSubmission
|
StudentSubmission,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
me: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
submissions() {
|
||||||
|
return this.assignment.submissions.filter((submission) => {
|
||||||
|
return this.belongsToSchool(submission);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
currentFilter() {
|
||||||
data() {
|
return this.me.selectedClass;
|
||||||
return {
|
|
||||||
me: {}
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
methods: {
|
||||||
submissions() {
|
submissionLink(submission) {
|
||||||
return this.assignment.submissions.filter(submission => {
|
return `/submission/${submission.id}`;
|
||||||
return this.belongsToSchool(submission);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
currentFilter() {
|
|
||||||
return this.me.selectedClass;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
belongsToSchool(submission) {
|
||||||
methods: {
|
if (this.currentFilter.id === '') {
|
||||||
submissionLink(submission) {
|
return true;
|
||||||
return `/submission/${submission.id}`;
|
|
||||||
},
|
|
||||||
belongsToSchool(submission) {
|
|
||||||
if (this.currentFilter.id === '') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return submission.student.schoolClasses.some(schoolClass => schoolClass .id === this.currentFilter.id);
|
|
||||||
}
|
}
|
||||||
|
return submission.student.schoolClasses.some((schoolClass) => schoolClass.id === this.currentFilter.id);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
me: meQuery
|
me: meQuery,
|
||||||
}
|
},
|
||||||
|
};
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.assignment-with-submissions {
|
|
||||||
&__title {
|
|
||||||
font-size: toRem(35px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
font-size: toRem(26px);
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__solution {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__heading {
|
|
||||||
font-size: toRem(17px);
|
|
||||||
font-weight: 800;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__submissions {
|
|
||||||
margin-top: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__no-submissions {
|
|
||||||
margin-top: $large-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(ul) {
|
|
||||||
@include list-parent;
|
|
||||||
}
|
|
||||||
:deep(li) {
|
|
||||||
@include list-child;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.assignment-with-submissions {
|
||||||
|
&__title {
|
||||||
|
font-size: toRem(35px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.submissions {
|
&__text {
|
||||||
width: 100%;
|
font-size: toRem(26px);
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submission-header {
|
&__solution {
|
||||||
&__title {
|
margin-bottom: 1rem;
|
||||||
color: $color-silver-dark;
|
|
||||||
font-family: $sans-serif-font-family;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
font-size: toRem(17px);
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__submissions {
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__no-submissions {
|
||||||
|
margin-top: $large-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(ul) {
|
||||||
|
@include list-parent;
|
||||||
|
}
|
||||||
|
:deep(li) {
|
||||||
|
@include list-child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submissions {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submission-header {
|
||||||
|
&__title {
|
||||||
|
color: $color-silver-dark;
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,68 @@
|
||||||
<template>
|
<template>
|
||||||
<router-link
|
<router-link :to="to" data-cy="back-link" class="sub-navigation-item back-link">
|
||||||
:to="to"
|
|
||||||
data-cy="back-link"
|
|
||||||
class="sub-navigation-item back-link"
|
|
||||||
>
|
|
||||||
<chevron-left class="back-link__icon sub-navigation-item__icon" />
|
<chevron-left class="back-link__icon sub-navigation-item__icon" />
|
||||||
{{ fullTitle }}
|
{{ fullTitle }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { MODULE_PAGE } from '@/router/module.names';
|
import { MODULE_PAGE } from '@/router/module.names';
|
||||||
import { ROOMS_PAGE } from '@/router/room.names';
|
import { ROOMS_PAGE } from '@/router/room.names';
|
||||||
import { PROJECTS_PAGE } from '@/router/portfolio.names';
|
import { PROJECTS_PAGE } from '@/router/portfolio.names';
|
||||||
|
|
||||||
const ChevronLeft = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronLeft');
|
const ChevronLeft = () => import(/* webpackChunkName: "icons" */ '@/components/icons/ChevronLeft');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: 'topic',
|
|
||||||
},
|
|
||||||
slug: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
type: {
|
||||||
components: {
|
type: String,
|
||||||
ChevronLeft,
|
default: 'topic',
|
||||||
},
|
},
|
||||||
|
slug: {
|
||||||
computed: {
|
type: String,
|
||||||
to() {
|
default: '',
|
||||||
switch (this.type) {
|
|
||||||
case 'topic':
|
|
||||||
return {name: 'topic', params: {topicSlug: this.slug}};
|
|
||||||
case 'module':
|
|
||||||
return {name: MODULE_PAGE};
|
|
||||||
case 'portfolio':
|
|
||||||
return {name: PROJECTS_PAGE};
|
|
||||||
default:
|
|
||||||
return {name: ROOMS_PAGE};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fullTitle() {
|
|
||||||
switch (this.type) {
|
|
||||||
case 'topic':
|
|
||||||
return `${this.$flavor.textTopic}: ${this.title}`;
|
|
||||||
case 'module':
|
|
||||||
return `${this.$flavor.textModule}: ${this.title}`;
|
|
||||||
default:
|
|
||||||
return this.title;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ChevronLeft,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
to() {
|
||||||
|
switch (this.type) {
|
||||||
|
case 'topic':
|
||||||
|
return { name: 'topic', params: { topicSlug: this.slug } };
|
||||||
|
case 'module':
|
||||||
|
return { name: MODULE_PAGE };
|
||||||
|
case 'portfolio':
|
||||||
|
return { name: PROJECTS_PAGE };
|
||||||
|
default:
|
||||||
|
return { name: ROOMS_PAGE };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fullTitle() {
|
||||||
|
switch (this.type) {
|
||||||
|
case 'topic':
|
||||||
|
return `${this.$flavor.textTopic}: ${this.title}`;
|
||||||
|
case 'module':
|
||||||
|
return `${this.$flavor.textModule}: ${this.title}`;
|
||||||
|
default:
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.back-link {
|
.back-link {
|
||||||
@include regular-text;
|
@include regular-text;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :data-scrollto="chapter.id" class="chapter" data-cy="chapter">
|
||||||
:data-scrollto="chapter.id"
|
<div :class="{ 'hideable-element--greyed-out': titleGreyedOut }" class="hideable-element" v-if="!titleHidden">
|
||||||
class="chapter"
|
<h3 :id="'chapter-' + index">
|
||||||
data-cy="chapter"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
:class="{'hideable-element--greyed-out': titleGreyedOut}"
|
|
||||||
class="hideable-element"
|
|
||||||
v-if="!titleHidden"
|
|
||||||
>
|
|
||||||
<h3
|
|
||||||
:id="'chapter-' + index"
|
|
||||||
>
|
|
||||||
{{ chapter.title }}
|
{{ chapter.title }}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<visibility-action
|
<visibility-action :block="chapter" type="chapter-title" v-if="editMode" />
|
||||||
:block="chapter"
|
|
||||||
type="chapter-title"
|
|
||||||
v-if="editMode"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<bookmark-actions
|
<bookmark-actions
|
||||||
:bookmarked="!!chapter.bookmark"
|
:bookmarked="!!chapter.bookmark"
|
||||||
|
|
@ -33,27 +19,17 @@
|
||||||
@bookmark="bookmark(!chapter.bookmark)"
|
@bookmark="bookmark(!chapter.bookmark)"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
:class="{'hideable-element--greyed-out': descriptionGreyedOut}"
|
:class="{ 'hideable-element--greyed-out': descriptionGreyedOut }"
|
||||||
class="chapter__intro intro hideable-element"
|
class="chapter__intro intro hideable-element"
|
||||||
v-if="!descriptionHidden"
|
v-if="!descriptionHidden"
|
||||||
>
|
>
|
||||||
<visibility-action
|
<visibility-action :block="chapter" :chapter="true" type="chapter-description" v-if="editMode" />
|
||||||
:block="chapter"
|
<p class="chapter__description">
|
||||||
:chapter="true"
|
|
||||||
type="chapter-description"
|
|
||||||
v-if="editMode"
|
|
||||||
/>
|
|
||||||
<p
|
|
||||||
class="chapter__description"
|
|
||||||
>
|
|
||||||
{{ chapter.description }}
|
{{ chapter.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-content-button
|
<add-content-button :where="{ parent: chapter }" v-if="editMode" />
|
||||||
:where="{parent: chapter}"
|
|
||||||
v-if="editMode"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<content-block
|
<content-block
|
||||||
:content-block="contentBlock"
|
:content-block="contentBlock"
|
||||||
|
|
@ -66,177 +42,179 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentBlock from '@/components/ContentBlock';
|
import ContentBlock from '@/components/ContentBlock';
|
||||||
import AddContentButton from '@/components/AddContentButton';
|
import AddContentButton from '@/components/AddContentButton';
|
||||||
import BookmarkActions from '@/components/notes/BookmarkActions';
|
import BookmarkActions from '@/components/notes/BookmarkActions';
|
||||||
import VisibilityAction from '@/components/visibility/VisibilityAction';
|
import VisibilityAction from '@/components/visibility/VisibilityAction';
|
||||||
|
|
||||||
import {hidden} from '@/helpers/visibility';
|
import { hidden } from '@/helpers/visibility';
|
||||||
import {CHAPTER_DESCRIPTION_TYPE, CHAPTER_TITLE_TYPE, CONTENT_TYPE} from '@/consts/types';
|
import { CHAPTER_DESCRIPTION_TYPE, CHAPTER_TITLE_TYPE, CONTENT_TYPE } from '@/consts/types';
|
||||||
|
|
||||||
import UPDATE_CHAPTER_BOOKMARK_MUTATION from '@/graphql/gql/mutations/updateChapterBookmark.gql';
|
import UPDATE_CHAPTER_BOOKMARK_MUTATION from '@/graphql/gql/mutations/updateChapterBookmark.gql';
|
||||||
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
||||||
|
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
chapter: {
|
chapter: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0,
|
||||||
},
|
},
|
||||||
editMode: {
|
editMode: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [me],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
BookmarkActions,
|
||||||
|
VisibilityAction,
|
||||||
|
ContentBlock,
|
||||||
|
AddContentButton,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
filteredContentBlocks() {
|
||||||
|
if (!(this.chapter && this.chapter.contentBlocks)) {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
if (this.editMode) {
|
||||||
|
return this.chapter.contentBlocks;
|
||||||
|
}
|
||||||
|
return this.chapter.contentBlocks.filter(
|
||||||
|
(contentBlock) =>
|
||||||
|
!hidden({
|
||||||
|
block: contentBlock,
|
||||||
|
schoolClass: this.schoolClass,
|
||||||
|
type: CONTENT_TYPE,
|
||||||
|
})
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
note() {
|
||||||
mixins: [me],
|
if (this.chapter && this.chapter.bookmark) {
|
||||||
|
return this.chapter.bookmark.note;
|
||||||
components: {
|
}
|
||||||
BookmarkActions,
|
return false;
|
||||||
VisibilityAction,
|
|
||||||
ContentBlock,
|
|
||||||
AddContentButton,
|
|
||||||
},
|
},
|
||||||
|
titleGreyedOut() {
|
||||||
computed: {
|
return this.textHidden(CHAPTER_TITLE_TYPE) && this.editMode;
|
||||||
filteredContentBlocks() {
|
|
||||||
if (!(this.chapter && this.chapter.contentBlocks)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (this.editMode) {
|
|
||||||
return this.chapter.contentBlocks;
|
|
||||||
}
|
|
||||||
return this.chapter.contentBlocks.filter(contentBlock => !hidden({
|
|
||||||
block: contentBlock,
|
|
||||||
schoolClass: this.schoolClass,
|
|
||||||
type: CONTENT_TYPE,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
note() {
|
|
||||||
if (this.chapter && this.chapter.bookmark) {
|
|
||||||
return this.chapter.bookmark.note;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
titleGreyedOut() {
|
|
||||||
return this.textHidden(CHAPTER_TITLE_TYPE) && this.editMode;
|
|
||||||
},
|
|
||||||
// never hidden when editing the module
|
|
||||||
titleHidden() {
|
|
||||||
if (this.chapter.titleHidden === true) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return this.textHidden(CHAPTER_TITLE_TYPE) && !this.editMode;
|
|
||||||
},
|
|
||||||
descriptionGreyedOut() {
|
|
||||||
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && this.editMode;
|
|
||||||
},
|
|
||||||
// never hidden when editing the module
|
|
||||||
descriptionHidden() {
|
|
||||||
if (this.chapter.descriptionHidden === true) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && !this.editMode;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
// never hidden when editing the module
|
||||||
|
titleHidden() {
|
||||||
|
if (this.chapter.titleHidden === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.textHidden(CHAPTER_TITLE_TYPE) && !this.editMode;
|
||||||
|
},
|
||||||
|
descriptionGreyedOut() {
|
||||||
|
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && this.editMode;
|
||||||
|
},
|
||||||
|
// never hidden when editing the module
|
||||||
|
descriptionHidden() {
|
||||||
|
if (this.chapter.descriptionHidden === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && !this.editMode;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
bookmark(bookmarked) {
|
bookmark(bookmarked) {
|
||||||
const id = this.chapter.id;
|
const id = this.chapter.id;
|
||||||
this.$apollo.mutate({
|
this.$apollo.mutate({
|
||||||
mutation: UPDATE_CHAPTER_BOOKMARK_MUTATION,
|
mutation: UPDATE_CHAPTER_BOOKMARK_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
chapter: id,
|
chapter: id,
|
||||||
bookmarked,
|
bookmarked,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
update: (store) => {
|
},
|
||||||
const query = CHAPTER_QUERY;
|
update: (store) => {
|
||||||
const variables = {id};
|
const query = CHAPTER_QUERY;
|
||||||
const {chapter} = store.readQuery({
|
const variables = { id };
|
||||||
query,
|
const { chapter } = store.readQuery({
|
||||||
variables,
|
query,
|
||||||
});
|
variables,
|
||||||
|
});
|
||||||
|
|
||||||
let bookmark;
|
let bookmark;
|
||||||
|
|
||||||
if (bookmarked) {
|
if (bookmarked) {
|
||||||
bookmark = {
|
bookmark = {
|
||||||
__typename: 'ChapterBookmarkNode',
|
__typename: 'ChapterBookmarkNode',
|
||||||
note: null,
|
note: null,
|
||||||
};
|
|
||||||
} else {
|
|
||||||
bookmark = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
chapter: {
|
|
||||||
...chapter,
|
|
||||||
bookmark
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
bookmark = null;
|
||||||
|
}
|
||||||
|
|
||||||
store.writeQuery({
|
const data = {
|
||||||
data,
|
chapter: {
|
||||||
query,
|
...chapter,
|
||||||
variables,
|
bookmark,
|
||||||
});
|
|
||||||
},
|
|
||||||
optimisticResponse: {
|
|
||||||
__typename: 'Mutation',
|
|
||||||
updateChapterBookmark: {
|
|
||||||
__typename: 'UpdateChapterBookmarkPayload',
|
|
||||||
success: true,
|
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
});
|
|
||||||
},
|
|
||||||
addNote(id) {
|
|
||||||
this.$store.dispatch('addNote', {
|
|
||||||
content: id,
|
|
||||||
parent: this.chapter.id,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
editNote() {
|
|
||||||
this.$store.dispatch('editNote', this.chapter.bookmark.note);
|
|
||||||
},
|
|
||||||
textHidden(type) {
|
|
||||||
return hidden({
|
|
||||||
block: this.chapter,
|
|
||||||
schoolClass: this.schoolClass,
|
|
||||||
type,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
store.writeQuery({
|
||||||
|
data,
|
||||||
|
query,
|
||||||
|
variables,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: 'Mutation',
|
||||||
|
updateChapterBookmark: {
|
||||||
|
__typename: 'UpdateChapterBookmarkPayload',
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addNote(id) {
|
||||||
|
this.$store.dispatch('addNote', {
|
||||||
|
content: id,
|
||||||
|
parent: this.chapter.id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
editNote() {
|
||||||
|
this.$store.dispatch('editNote', this.chapter.bookmark.note);
|
||||||
|
},
|
||||||
|
textHidden(type) {
|
||||||
|
return hidden({
|
||||||
|
block: this.chapter,
|
||||||
|
schoolClass: this.schoolClass,
|
||||||
|
type,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.chapter {
|
.chapter {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&__bookmark-actions {
|
&__bookmark-actions {
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
}
|
|
||||||
|
|
||||||
&__intro {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__description {
|
|
||||||
@include lead-paragraph;
|
|
||||||
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__intro {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
@include lead-paragraph;
|
||||||
|
|
||||||
|
margin-bottom: $large-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,92 +1,86 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="color-chooser">
|
<div class="color-chooser">
|
||||||
<div
|
<div
|
||||||
:class="{'color-chooser__color-wrapper--selected': selectedColor === color.name}"
|
:class="{ 'color-chooser__color-wrapper--selected': selectedColor === color.name }"
|
||||||
class="color-chooser__color-wrapper"
|
class="color-chooser__color-wrapper"
|
||||||
data-cy="color-select"
|
data-cy="color-select"
|
||||||
v-for="(color, index) in colors"
|
v-for="(color, index) in colors"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="$emit('input', color.name)"
|
@click="$emit('input', color.name)"
|
||||||
>
|
>
|
||||||
<div
|
<div :class="'color-chooser__color--' + color.name" class="color-chooser__color">
|
||||||
:class="'color-chooser__color--' + color.name"
|
<tick class="color-chooser__selected-icon" v-if="selectedColor === color.name" />
|
||||||
class="color-chooser__color"
|
|
||||||
>
|
|
||||||
<tick
|
|
||||||
class="color-chooser__selected-icon"
|
|
||||||
v-if="selectedColor === color.name"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const Tick = () => import(/* webpackChunkName: "icons" */'@/components/icons/Tick');
|
const Tick = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Tick');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['selectedColor'],
|
props: ['selectedColor'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Tick
|
Tick,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
colors: [
|
colors: [
|
||||||
{
|
{
|
||||||
name: 'yellow'
|
name: 'yellow',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'blue'
|
name: 'blue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'red'
|
name: 'red',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'green'
|
name: 'green',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.color-chooser {
|
.color-chooser {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
&__color-wrapper {
|
&__color-wrapper {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
&--selected {
|
&--selected {
|
||||||
border: 1px solid $color-charcoal-dark;
|
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-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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{'hideable-element--greyed-out': hidden}"
|
:class="{ 'hideable-element--greyed-out': hidden }"
|
||||||
class="content-block__container hideable-element content-list__parent"
|
class="content-block__container hideable-element content-list__parent"
|
||||||
>
|
>
|
||||||
<div
|
<div :class="specialClass" :style="instrumentStyle" class="content-block" data-cy="content-block">
|
||||||
:class="specialClass"
|
<div class="block-actions" v-if="canEditModule && !isInstrumentBlock">
|
||||||
:style="instrumentStyle"
|
<user-widget v-bind="me" class="block-actions__user-widget content-block__user-widget" v-if="isMine" />
|
||||||
class="content-block"
|
|
||||||
data-cy="content-block"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="block-actions"
|
|
||||||
v-if="canEditModule && !isInstrumentBlock"
|
|
||||||
>
|
|
||||||
<user-widget
|
|
||||||
v-bind="me"
|
|
||||||
class="block-actions__user-widget content-block__user-widget"
|
|
||||||
v-if="isMine"
|
|
||||||
/>
|
|
||||||
<more-options-widget>
|
<more-options-widget>
|
||||||
<li
|
<li class="popover-links__link" v-if="!isInstrumentBlock">
|
||||||
class="popover-links__link"
|
|
||||||
v-if="!isInstrumentBlock"
|
|
||||||
>
|
|
||||||
<popover-link
|
<popover-link
|
||||||
data-cy="duplicate-content-block-link"
|
data-cy="duplicate-content-block-link"
|
||||||
text="Duplizieren"
|
text="Duplizieren"
|
||||||
@link-action="duplicateContentBlock(contentBlock)"
|
@link-action="duplicateContentBlock(contentBlock)"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li class="popover-links__link" v-if="isMine">
|
||||||
class="popover-links__link"
|
|
||||||
v-if="isMine"
|
|
||||||
>
|
|
||||||
<popover-link
|
<popover-link
|
||||||
data-cy="delete-content-block-link"
|
data-cy="delete-content-block-link"
|
||||||
text="Löschen"
|
text="Löschen"
|
||||||
|
|
@ -40,22 +22,13 @@
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li
|
<li class="popover-links__link" v-if="isMine">
|
||||||
class="popover-links__link"
|
<popover-link text="Bearbeiten" @link-action="editContentBlock(contentBlock)" />
|
||||||
v-if="isMine"
|
|
||||||
>
|
|
||||||
<popover-link
|
|
||||||
text="Bearbeiten"
|
|
||||||
@link-action="editContentBlock(contentBlock)"
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</more-options-widget>
|
</more-options-widget>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-block__visibility">
|
<div class="content-block__visibility">
|
||||||
<visibility-action
|
<visibility-action :block="contentBlock" v-if="canEditModule" />
|
||||||
:block="contentBlock"
|
|
||||||
v-if="canEditModule"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3
|
<h3
|
||||||
|
|
@ -66,10 +39,7 @@
|
||||||
>
|
>
|
||||||
{{ instrumentLabel }}
|
{{ instrumentLabel }}
|
||||||
</h3>
|
</h3>
|
||||||
<h4
|
<h4 class="content-block__title" v-if="!contentBlock.indent">
|
||||||
class="content-block__title"
|
|
||||||
v-if="!contentBlock.indent"
|
|
||||||
>
|
|
||||||
{{ contentBlock.title }}
|
{{ contentBlock.title }}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
|
|
@ -85,109 +55,107 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-content-button
|
<add-content-button :where="{ after: contentBlock }" v-if="canEditModule" />
|
||||||
:where="{after: contentBlock}"
|
|
||||||
v-if="canEditModule"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AddContentButton from '@/components/AddContentButton';
|
import AddContentButton from '@/components/AddContentButton';
|
||||||
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
|
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
|
||||||
import UserWidget from '@/components/UserWidget';
|
import UserWidget from '@/components/UserWidget';
|
||||||
import VisibilityAction from '@/components/visibility/VisibilityAction';
|
import VisibilityAction from '@/components/visibility/VisibilityAction';
|
||||||
|
|
||||||
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
||||||
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
|
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
|
||||||
import DUPLICATE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/duplicateContentBlock.gql';
|
import DUPLICATE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/duplicateContentBlock.gql';
|
||||||
|
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
|
|
||||||
import {hidden} from '@/helpers/visibility';
|
import { hidden } from '@/helpers/visibility';
|
||||||
import {CONTENT_TYPE} from '@/consts/types';
|
import { CONTENT_TYPE } from '@/consts/types';
|
||||||
import PopoverLink from '@/components/ui/PopoverLink';
|
import PopoverLink from '@/components/ui/PopoverLink';
|
||||||
import {insertAtIndex, removeAtIndex} from '@/graphql/immutable-operations';
|
import { insertAtIndex, removeAtIndex } from '@/graphql/immutable-operations';
|
||||||
import {EDIT_CONTENT_BLOCK_PAGE} from '@/router/module.names';
|
import { EDIT_CONTENT_BLOCK_PAGE } from '@/router/module.names';
|
||||||
import {instrumentCategory} from '@/helpers/instrumentType';
|
import { instrumentCategory } from '@/helpers/instrumentType';
|
||||||
|
|
||||||
const ContentComponent = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ContentComponent');
|
const ContentComponent = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ContentComponent');
|
||||||
|
|
||||||
|
export default {
|
||||||
export default {
|
name: 'ContentBlock',
|
||||||
name: 'ContentBlock',
|
props: {
|
||||||
props: {
|
contentBlock: {
|
||||||
contentBlock: {
|
type: Object,
|
||||||
type: Object,
|
default: () => ({}),
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
parent: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
editMode: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
parent: {
|
||||||
mixins: [me],
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
components: {
|
|
||||||
PopoverLink,
|
|
||||||
ContentComponent,
|
|
||||||
AddContentButton,
|
|
||||||
VisibilityAction,
|
|
||||||
MoreOptionsWidget,
|
|
||||||
UserWidget,
|
|
||||||
},
|
},
|
||||||
|
editMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
mixins: [me],
|
||||||
canEditModule() {
|
|
||||||
return !this.contentBlock.indent && this.editMode;
|
components: {
|
||||||
},
|
PopoverLink,
|
||||||
specialClass() {
|
ContentComponent,
|
||||||
return `content-block--${this.contentBlock.type.toLowerCase()}`;
|
AddContentButton,
|
||||||
},
|
VisibilityAction,
|
||||||
isInstrumentBlock() {
|
MoreOptionsWidget,
|
||||||
return !!this.contentBlock.instrumentCategory;
|
UserWidget,
|
||||||
},
|
},
|
||||||
// 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
|
|
||||||
instrumentStyle() {
|
computed: {
|
||||||
if (this.isInstrumentBlock) {
|
canEditModule() {
|
||||||
return {
|
return !this.contentBlock.indent && this.editMode;
|
||||||
backgroundColor: this.contentBlock.instrumentCategory.background
|
},
|
||||||
};
|
specialClass() {
|
||||||
}
|
return `content-block--${this.contentBlock.type.toLowerCase()}`;
|
||||||
return {};
|
},
|
||||||
},
|
isInstrumentBlock() {
|
||||||
instrumentLabel() {
|
return !!this.contentBlock.instrumentCategory;
|
||||||
const contentType = this.contentBlock.type.toLowerCase();
|
},
|
||||||
if (contentType.startsWith('base')) { // all legacy instruments start with `base`
|
// 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
|
||||||
return instrumentCategory(contentType);
|
instrumentStyle() {
|
||||||
}
|
if (this.isInstrumentBlock) {
|
||||||
if (this.isInstrumentBlock) {
|
return {
|
||||||
return instrumentCategory(this.contentBlock.instrumentCategory.name);
|
backgroundColor: this.contentBlock.instrumentCategory.background,
|
||||||
}
|
};
|
||||||
return '';
|
}
|
||||||
},
|
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
|
},
|
||||||
instrumentLabelStyle() {
|
instrumentLabel() {
|
||||||
if (this.isInstrumentBlock) {
|
const contentType = this.contentBlock.type.toLowerCase();
|
||||||
return {
|
if (contentType.startsWith('base')) {
|
||||||
color: this.contentBlock.instrumentCategory.foreground
|
// all legacy instruments start with `base`
|
||||||
};
|
return instrumentCategory(contentType);
|
||||||
}
|
}
|
||||||
return {};
|
if (this.isInstrumentBlock) {
|
||||||
},
|
return instrumentCategory(this.contentBlock.instrumentCategory.name);
|
||||||
canEditContentBlock() {
|
}
|
||||||
return this.isMine && !this.contentBlock.indent;
|
return '';
|
||||||
},
|
},
|
||||||
isMine() {
|
// 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
|
||||||
return this.contentBlock.mine;
|
instrumentLabelStyle() {
|
||||||
},
|
if (this.isInstrumentBlock) {
|
||||||
contentBlocksWithContentLists() {
|
return {
|
||||||
/*
|
color: this.contentBlock.instrumentCategory.foreground,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
canEditContentBlock() {
|
||||||
|
return this.isMine && !this.contentBlock.indent;
|
||||||
|
},
|
||||||
|
isMine() {
|
||||||
|
return this.contentBlock.mine;
|
||||||
|
},
|
||||||
|
contentBlocksWithContentLists() {
|
||||||
|
/*
|
||||||
collects all content_list_items in content_lists:
|
collects all content_list_items in content_lists:
|
||||||
{
|
{
|
||||||
text_block,
|
text_block,
|
||||||
|
|
@ -201,221 +169,238 @@
|
||||||
text_block
|
text_block
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
let contentList = [];
|
let contentList = [];
|
||||||
let newContent = this.contentBlock.contents.reduce((newContents, content, index) => {
|
let newContent = this.contentBlock.contents.reduce((newContents, content, index) => {
|
||||||
// collect content_list_items
|
// collect content_list_items
|
||||||
if (content.type === 'content_list_item') {
|
if (content.type === 'content_list_item') {
|
||||||
contentList = [...contentList, content];
|
contentList = [...contentList, content];
|
||||||
if (index === this.contentBlock.contents.length - 1) { // content is last element of contents array
|
if (index === this.contentBlock.contents.length - 1) {
|
||||||
let updatedContent = [...newContents, ...this.createContentListOrBlocks(contentList)];
|
// content is last element of contents array
|
||||||
return updatedContent;
|
let updatedContent = [...newContents, ...this.createContentListOrBlocks(contentList)];
|
||||||
}
|
return updatedContent;
|
||||||
|
}
|
||||||
|
return newContents;
|
||||||
|
} else {
|
||||||
|
// handle all other items and reset current content_list if necessary
|
||||||
|
if (contentList.length !== 0) {
|
||||||
|
newContents = [...newContents, ...this.createContentListOrBlocks(contentList), content];
|
||||||
|
contentList = [];
|
||||||
return newContents;
|
return newContents;
|
||||||
} else {
|
} else {
|
||||||
// handle all other items and reset current content_list if necessary
|
return [...newContents, content];
|
||||||
if (contentList.length !== 0) {
|
|
||||||
newContents = [...newContents, ...this.createContentListOrBlocks(contentList), content];
|
|
||||||
contentList = [];
|
|
||||||
return newContents;
|
|
||||||
} else {
|
|
||||||
return [...newContents, content];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, []);
|
}
|
||||||
return Object.assign({}, this.contentBlock, {
|
}, []);
|
||||||
contents: newContent,
|
return Object.assign({}, this.contentBlock, {
|
||||||
});
|
contents: newContent,
|
||||||
},
|
});
|
||||||
hidden() {
|
|
||||||
return hidden({
|
|
||||||
block: this.contentBlock,
|
|
||||||
schoolClass: this.schoolClass,
|
|
||||||
type: CONTENT_TYPE,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
root() {
|
|
||||||
// we need the root content block id, not the generated content block if inside a content list block
|
|
||||||
return this.contentBlock.root ? this.contentBlock.root : this.contentBlock.id;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
hidden() {
|
||||||
duplicateContentBlock({id}) {
|
return hidden({
|
||||||
const parent = this.parent;
|
block: this.contentBlock,
|
||||||
this.$apollo.mutate({
|
schoolClass: this.schoolClass,
|
||||||
mutation: DUPLICATE_CONTENT_BLOCK_MUTATION,
|
type: CONTENT_TYPE,
|
||||||
variables: {
|
});
|
||||||
input: {
|
},
|
||||||
id,
|
root() {
|
||||||
|
// we need the root content block id, not the generated content block if inside a content list block
|
||||||
|
return this.contentBlock.root ? this.contentBlock.root : this.contentBlock.id;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
duplicateContentBlock({ id }) {
|
||||||
|
const parent = this.parent;
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: DUPLICATE_CONTENT_BLOCK_MUTATION,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update(
|
||||||
|
store,
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
duplicateContentBlock: { contentBlock },
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
if (contentBlock) {
|
||||||
|
const query = CHAPTER_QUERY;
|
||||||
|
const variables = {
|
||||||
|
id: parent.id,
|
||||||
|
};
|
||||||
|
const { chapter } = store.readQuery({ query, variables });
|
||||||
|
const index = chapter.contentBlocks.findIndex((contentBlock) => contentBlock.id === id);
|
||||||
|
const contentBlocks = insertAtIndex(chapter.contentBlocks, index, contentBlock);
|
||||||
|
const data = {
|
||||||
|
chapter: {
|
||||||
|
...chapter,
|
||||||
|
contentBlocks,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
store.writeQuery({ query, variables, data });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
editContentBlock(contentBlock) {
|
||||||
|
const route = {
|
||||||
|
name: EDIT_CONTENT_BLOCK_PAGE,
|
||||||
|
params: {
|
||||||
|
id: contentBlock.id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.$router.push(route);
|
||||||
|
},
|
||||||
|
deleteContentBlock(contentBlock) {
|
||||||
|
this.$modal
|
||||||
|
.open('confirm')
|
||||||
|
.then(() => {
|
||||||
|
this.doDeleteContentBlock(contentBlock);
|
||||||
|
})
|
||||||
|
.catch();
|
||||||
|
},
|
||||||
|
doDeleteContentBlock(contentBlock) {
|
||||||
|
const parent = this.parent;
|
||||||
|
const id = contentBlock.id;
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: DELETE_CONTENT_BLOCK_MUTATION,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id,
|
||||||
},
|
},
|
||||||
update(store, {data: {duplicateContentBlock: {contentBlock}}}) {
|
},
|
||||||
if (contentBlock) {
|
update(
|
||||||
const query = CHAPTER_QUERY;
|
store,
|
||||||
const variables = {
|
{
|
||||||
id: parent.id,
|
data: {
|
||||||
};
|
deleteContentBlock: { success },
|
||||||
const {chapter} = store.readQuery({query, variables});
|
|
||||||
const index = chapter.contentBlocks.findIndex(contentBlock => contentBlock.id === id);
|
|
||||||
const contentBlocks = insertAtIndex(chapter.contentBlocks, index, contentBlock);
|
|
||||||
const data = {
|
|
||||||
chapter: {
|
|
||||||
...chapter,
|
|
||||||
contentBlocks,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
store.writeQuery({query, variables, data});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
editContentBlock(contentBlock) {
|
|
||||||
const route = {
|
|
||||||
name: EDIT_CONTENT_BLOCK_PAGE,
|
|
||||||
params: {
|
|
||||||
id: contentBlock.id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
this.$router.push(route);
|
|
||||||
},
|
|
||||||
deleteContentBlock(contentBlock) {
|
|
||||||
this.$modal.open('confirm').then(() => {
|
|
||||||
this.doDeleteContentBlock(contentBlock);
|
|
||||||
})
|
|
||||||
.catch();
|
|
||||||
},
|
|
||||||
doDeleteContentBlock(contentBlock) {
|
|
||||||
const parent = this.parent;
|
|
||||||
const id = contentBlock.id;
|
|
||||||
this.$apollo.mutate({
|
|
||||||
mutation: DELETE_CONTENT_BLOCK_MUTATION,
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
id,
|
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
update(store, {data: {deleteContentBlock: {success}}}) {
|
) {
|
||||||
if (success) {
|
if (success) {
|
||||||
const query = CHAPTER_QUERY;
|
const query = CHAPTER_QUERY;
|
||||||
const variables = {
|
const variables = {
|
||||||
id: parent.id,
|
id: parent.id,
|
||||||
};
|
};
|
||||||
const {chapter} = store.readQuery({query, variables});
|
const { chapter } = store.readQuery({ query, variables });
|
||||||
const index = chapter.contentBlocks.findIndex(contentBlock => contentBlock.id === id);
|
const index = chapter.contentBlocks.findIndex((contentBlock) => contentBlock.id === id);
|
||||||
const contentBlocks = removeAtIndex(chapter.contentBlocks, index);
|
const contentBlocks = removeAtIndex(chapter.contentBlocks, index);
|
||||||
const data = {
|
const data = {
|
||||||
chapter: {
|
chapter: {
|
||||||
...chapter,
|
...chapter,
|
||||||
contentBlocks,
|
contentBlocks,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
store.writeQuery({query, variables, data});
|
store.writeQuery({ query, variables, data });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createContentListOrBlocks(contentList) {
|
createContentListOrBlocks(contentList) {
|
||||||
return [{
|
return [
|
||||||
|
{
|
||||||
type: 'content_list',
|
type: 'content_list',
|
||||||
contents: contentList,
|
contents: contentList,
|
||||||
id: contentList[0].id,
|
id: contentList[0].id,
|
||||||
}];
|
},
|
||||||
},
|
];
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-block {
|
.content-block {
|
||||||
margin-bottom: $section-spacing;
|
margin-bottom: $section-spacing;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
&__container {
|
&__title {
|
||||||
position: relative;
|
line-height: 1.5;
|
||||||
|
margin-top: -0.5rem; // to offset the 1.5 line height, it leaves a padding on top
|
||||||
|
}
|
||||||
|
|
||||||
|
&__instrument-label {
|
||||||
|
margin-bottom: $medium-spacing;
|
||||||
|
@include regular-text();
|
||||||
|
}
|
||||||
|
|
||||||
|
&__action-button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__user-widget {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--base_communication {
|
||||||
|
@include content-box($color-accent-1-list);
|
||||||
|
|
||||||
|
.content-block__instrument-label {
|
||||||
|
color: $color-accent-1-dark;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__title {
|
&--task {
|
||||||
line-height: 1.5;
|
@include light-border(bottom);
|
||||||
margin-top: -0.5rem; // to offset the 1.5 line height, it leaves a padding on top
|
|
||||||
}
|
|
||||||
|
|
||||||
&__instrument-label {
|
.content-block__title {
|
||||||
margin-bottom: $medium-spacing;
|
color: $color-brand;
|
||||||
@include regular-text();
|
margin-top: $default-padding;
|
||||||
}
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
&__action-button {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__user-widget {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--base_communication {
|
|
||||||
@include content-box($color-accent-1-list);
|
|
||||||
|
|
||||||
.content-block__instrument-label {
|
|
||||||
color: $color-accent-1-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--task {
|
|
||||||
@include light-border(bottom);
|
@include light-border(bottom);
|
||||||
|
|
||||||
.content-block__title {
|
@include desktop {
|
||||||
color: $color-brand;
|
margin-top: 0;
|
||||||
margin-top: $default-padding;
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
@include light-border(bottom);
|
|
||||||
|
|
||||||
@include desktop {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--base_society {
|
|
||||||
@include content-box($color-accent-2-list);
|
|
||||||
|
|
||||||
.content-block__instrument-label {
|
|
||||||
color: $color-accent-2-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--base_interdisciplinary {
|
|
||||||
@include content-box($color-accent-4-list);
|
|
||||||
|
|
||||||
.content-block__instrument-label {
|
|
||||||
color: $color-accent-4-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--instrument {
|
|
||||||
@include content-box-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(p) {
|
|
||||||
line-height: 1.5;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.text-block) {
|
|
||||||
ul {
|
|
||||||
@include list-parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
@include list-child;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--base_society {
|
||||||
|
@include content-box($color-accent-2-list);
|
||||||
|
|
||||||
|
.content-block__instrument-label {
|
||||||
|
color: $color-accent-2-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--base_interdisciplinary {
|
||||||
|
@include content-box($color-accent-4-list);
|
||||||
|
|
||||||
|
.content-block__instrument-label {
|
||||||
|
color: $color-accent-4-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--instrument {
|
||||||
|
@include content-box-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(p) {
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.text-block) {
|
||||||
|
ul {
|
||||||
|
@include list-parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
@include list-child;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal :hide-header="true" :fullscreen="true" class="fullscreen-image">
|
||||||
:hide-header="true"
|
<img :src="imageUrl" class="fullscreen-image__image" />
|
||||||
:fullscreen="true"
|
|
||||||
class="fullscreen-image"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
:src="imageUrl"
|
|
||||||
class="fullscreen-image__image"
|
|
||||||
>
|
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Modal
|
Modal,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
imageUrl() {
|
||||||
|
return this.$store.state.imageUrl;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
computed: {
|
};
|
||||||
imageUrl() {
|
|
||||||
return this.$store.state.imageUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.fullscreen-image {
|
.fullscreen-image {
|
||||||
&__image {
|
&__image {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,35 @@
|
||||||
<template>
|
<template>
|
||||||
<modal :fullscreen="true">
|
<modal :fullscreen="true">
|
||||||
<component
|
<component :value="value" :is="type" />
|
||||||
:value="value"
|
|
||||||
:is="type"
|
|
||||||
/>
|
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
const InfogramBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InfogramBlock');
|
const InfogramBlock = () =>
|
||||||
const GeniallyBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/GeniallyBlock');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/InfogramBlock');
|
||||||
|
const GeniallyBlock = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/GeniallyBlock');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
InfogramBlock,
|
InfogramBlock,
|
||||||
GeniallyBlock
|
GeniallyBlock,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
id() {
|
||||||
|
return this.$store.state.infographic.id;
|
||||||
},
|
},
|
||||||
|
type() {
|
||||||
computed: {
|
return this.$store.state.infographic.type;
|
||||||
id() {
|
},
|
||||||
return this.$store.state.infographic.id;
|
value() {
|
||||||
},
|
return {
|
||||||
type() {
|
id: this.id,
|
||||||
return this.$store.state.infographic.type;
|
};
|
||||||
},
|
},
|
||||||
value() {
|
},
|
||||||
return {
|
};
|
||||||
id: this.id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal :hide-header="true" :fullscreen="true" class="fullscreen-video">
|
||||||
:hide-header="true"
|
|
||||||
:fullscreen="true"
|
|
||||||
class="fullscreen-video"
|
|
||||||
>
|
|
||||||
<iframe
|
<iframe
|
||||||
:src="src"
|
:src="src"
|
||||||
width="2000"
|
width="2000"
|
||||||
|
|
@ -18,31 +14,31 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Modal
|
Modal,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
vimeoId() {
|
||||||
|
return this.$store.state.vimeoId;
|
||||||
},
|
},
|
||||||
|
src() {
|
||||||
computed: {
|
return `https://player.vimeo.com/video/${this.vimeoId}`;
|
||||||
vimeoId() {
|
},
|
||||||
return this.$store.state.vimeoId;
|
},
|
||||||
},
|
};
|
||||||
src() {
|
|
||||||
return `https://player.vimeo.com/video/${this.vimeoId}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.fullscreen-video {
|
.fullscreen-video {
|
||||||
&__embed {
|
&__embed {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 95vh;
|
height: 95vh;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,139 +1,126 @@
|
||||||
<template>
|
<template>
|
||||||
<header class="header-bar">
|
<header class="header-bar">
|
||||||
<a
|
<a class="header-bar__sidebar-link" data-cy="open-sidebar-link" @click.stop="openSidebar('navigation')">
|
||||||
class="header-bar__sidebar-link"
|
|
||||||
data-cy="open-sidebar-link"
|
|
||||||
@click.stop="openSidebar('navigation')"
|
|
||||||
>
|
|
||||||
<hamburger class="header-bar__sidebar-icon" />
|
<hamburger class="header-bar__sidebar-icon" />
|
||||||
</a>
|
</a>
|
||||||
<content-navigation class="header-bar__content-navigation" />
|
<content-navigation class="header-bar__content-navigation" />
|
||||||
<div class="user-header">
|
<div class="user-header">
|
||||||
<a
|
<a class="user-header__sidebar-link">
|
||||||
class="user-header__sidebar-link"
|
<current-class class="user-header__current-class" @click.native.stop="openSidebar('profile')" />
|
||||||
>
|
|
||||||
<current-class
|
|
||||||
class="user-header__current-class"
|
|
||||||
@click.native.stop="openSidebar('profile')"
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<user-widget
|
<user-widget v-bind="me" data-cy="header-user-widget" @click.native.stop="openSidebar('profile')" />
|
||||||
v-bind="me"
|
|
||||||
data-cy="header-user-widget"
|
|
||||||
@click.native.stop="openSidebar('profile')"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation.vue';
|
import ContentNavigation from '@/components/book-navigation/ContentNavigation.vue';
|
||||||
import UserWidget from '@/components/UserWidget.vue';
|
import UserWidget from '@/components/UserWidget.vue';
|
||||||
import CurrentClass from '@/components/school-class/CurrentClass';
|
import CurrentClass from '@/components/school-class/CurrentClass';
|
||||||
|
|
||||||
import openSidebar from '@/mixins/open-sidebar';
|
import openSidebar from '@/mixins/open-sidebar';
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
|
|
||||||
const Hamburger = () => import(/* webpackChunkName: "icons" */'@/components/icons/Hamburger');
|
const Hamburger = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Hamburger');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [openSidebar, me],
|
mixins: [openSidebar, me],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ContentNavigation,
|
ContentNavigation,
|
||||||
UserWidget,
|
UserWidget,
|
||||||
CurrentClass,
|
CurrentClass,
|
||||||
Hamburger,
|
Hamburger,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.header-bar {
|
.header-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@supports (display: grid) {
|
@supports (display: grid) {
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
}
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
grid-auto-rows: 50px;
|
grid-auto-rows: 50px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
|
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
grid-template-columns: 50px 1fr auto;
|
grid-template-columns: 50px 1fr auto;
|
||||||
grid-template-rows: 50px;
|
grid-template-rows: 50px;
|
||||||
grid-auto-rows: auto;
|
grid-auto-rows: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For IE10+
|
* For IE10+
|
||||||
*/
|
*/
|
||||||
-ms-grid-columns: 1fr 1fr 1fr;
|
-ms-grid-columns: 1fr 1fr 1fr;
|
||||||
-ms-grid-rows: 50px 50px;
|
-ms-grid-rows: 50px 50px;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For IE10+
|
* For IE10+
|
||||||
*/
|
*/
|
||||||
& > :nth-child(1) {
|
& > :nth-child(1) {
|
||||||
-ms-grid-column: 1;
|
-ms-grid-column: 1;
|
||||||
-ms-grid-row-align: center;
|
-ms-grid-row-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__content-navigation {
|
&__content-navigation {
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sidebar-link {
|
&__sidebar-link {
|
||||||
padding: $small-spacing;
|
padding: $small-spacing;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sidebar-icon {
|
&__sidebar-icon {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For IE10+
|
* For IE10+
|
||||||
*/
|
*/
|
||||||
& > :nth-child(3) {
|
& > :nth-child(3) {
|
||||||
-ms-grid-column: 3;
|
-ms-grid-column: 3;
|
||||||
-ms-grid-row-align: center;
|
-ms-grid-row-align: center;
|
||||||
-ms-grid-column-align: end;
|
-ms-grid-column-align: end;
|
||||||
|
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
}
|
|
||||||
|
|
||||||
& > :nth-child(4) {
|
|
||||||
-ms-grid-row: 2;
|
|
||||||
-ms-grid-column: 1;
|
|
||||||
-ms-grid-column-span: 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-header {
|
& > :nth-child(4) {
|
||||||
display: flex;
|
-ms-grid-row: 2;
|
||||||
|
-ms-grid-column: 1;
|
||||||
|
-ms-grid-column-span: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__current-class {
|
.user-header {
|
||||||
margin-right: $large-spacing;
|
display: flex;
|
||||||
}
|
|
||||||
|
|
||||||
&__sidebar-link {
|
&__current-class {
|
||||||
cursor: pointer;
|
margin-right: $large-spacing;
|
||||||
display: none;
|
}
|
||||||
|
|
||||||
@include desktop {
|
&__sidebar-link {
|
||||||
display: flex;
|
cursor: pointer;
|
||||||
}
|
display: none;
|
||||||
|
|
||||||
|
@include desktop {
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -10,66 +10,65 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const InfoIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon');
|
const InfoIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['text'],
|
props: ['text'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
InfoIcon
|
InfoIcon,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.helpful-tooltip {
|
.helpful-tooltip {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
fill: $color-silver-dark;
|
fill: $color-silver-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tooltip {
|
&__tooltip {
|
||||||
visibility: hidden;
|
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;
|
position: absolute;
|
||||||
left: 30px;
|
left: 0;
|
||||||
top: 0px;
|
top: 18px;
|
||||||
width: 400px;
|
margin-left: -1px;
|
||||||
}
|
border-left: 1px solid $color-silver-dark;
|
||||||
|
border-top: 1px solid $color-silver-dark;
|
||||||
&__text {
|
|
||||||
display: inline-table;
|
|
||||||
width: auto;
|
|
||||||
|
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
border: 1px solid $color-silver-dark;
|
width: 10px;
|
||||||
border-radius: 5px;
|
height: 10px;
|
||||||
padding: $small-spacing;
|
transform: rotate(-45deg) translateY(-50%);
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover &__tooltip {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,51 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button :disabled="loading || disabled" class="loading-button button button--primary button--big">
|
||||||
:disabled="loading || disabled"
|
|
||||||
class="loading-button button button--primary button--big"
|
|
||||||
>
|
|
||||||
<template v-if="!loading">
|
<template v-if="!loading">
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</template>
|
</template>
|
||||||
<loading-icon
|
<loading-icon class="loading-button__icon" v-else />
|
||||||
class="loading-button__icon"
|
|
||||||
v-else
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const LoadingIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/LoadingIcon');
|
const LoadingIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/LoadingIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
loading: {
|
loading: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
components: {
|
disabled: {
|
||||||
LoadingIcon
|
type: Boolean,
|
||||||
}
|
default: false,
|
||||||
};
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
LoadingIcon,
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.loading-button {
|
.loading-button {
|
||||||
height: 52px;
|
height: 52px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@include spin;
|
@include spin;
|
||||||
fill: $color-brand;
|
fill: $color-brand;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="logout-widget">
|
<div class="logout-widget">
|
||||||
<a
|
<a class="logout-widget__logout" data-cy="logout" @click="logout()">Abmelden</a>
|
||||||
class="logout-widget__logout"
|
|
||||||
data-cy="logout"
|
|
||||||
@click="logout()"
|
|
||||||
>Abmelden</a>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LOGOUT_MUTATION from '@/graphql/gql/mutations/logoutUser.gql';
|
import LOGOUT_MUTATION from '@/graphql/gql/mutations/logoutUser.gql';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
logout() {
|
logout() {
|
||||||
this.$apollo.mutate({
|
this.$apollo
|
||||||
|
.mutate({
|
||||||
mutation: LOGOUT_MUTATION,
|
mutation: LOGOUT_MUTATION,
|
||||||
}).then(({data}) => {
|
})
|
||||||
if (data.logout.success) { location.replace('/logout'); }
|
.then(({ data }) => {
|
||||||
|
if (data.logout.success) {
|
||||||
|
location.replace('/logout');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.logout-widget {
|
.logout-widget {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__logout {
|
&__logout {
|
||||||
@include default-link;
|
@include default-link;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -4,65 +4,59 @@
|
||||||
<hamburger class="mobile-header__hamburger" />
|
<hamburger class="mobile-header__hamburger" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<router-link
|
<router-link to="/" data-cy="mobile-home-link">
|
||||||
to="/"
|
|
||||||
data-cy="mobile-home-link"
|
|
||||||
>
|
|
||||||
<logo />
|
<logo />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<user-widget
|
<user-widget v-bind="me" @click.native.stop="openSidebar('profile')" />
|
||||||
v-bind="me"
|
|
||||||
@click.native.stop="openSidebar('profile')"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import UserWidget from '@/components/UserWidget';
|
import UserWidget from '@/components/UserWidget';
|
||||||
|
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
import openSidebar from '@/mixins/open-sidebar';
|
import openSidebar from '@/mixins/open-sidebar';
|
||||||
|
|
||||||
const Logo = () => import(/* webpackChunkName: "icons" */'@/components/icons/Logo');
|
const Logo = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Logo');
|
||||||
const Hamburger = () => import(/* webpackChunkName: "icons" */'@/components/icons/Hamburger');
|
const Hamburger = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Hamburger');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [me, openSidebar],
|
mixins: [me, openSidebar],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Logo,
|
Logo,
|
||||||
Hamburger,
|
Hamburger,
|
||||||
UserWidget,
|
UserWidget,
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
showMobileNavigation() {
|
||||||
|
this.$store.dispatch('showMobileNavigation', true);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
methods: {
|
};
|
||||||
showMobileNavigation() {
|
|
||||||
this.$store.dispatch('showMobileNavigation', true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.mobile-header {
|
.mobile-header {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
|
||||||
|
|
||||||
padding: 0 $medium-spacing;
|
|
||||||
|
|
||||||
&__hamburger {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
fill: $color-silver-dark;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
padding: 0 $medium-spacing;
|
||||||
|
|
||||||
|
&__hamburger {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
fill: $color-silver-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="modal__backdrop">
|
<div class="modal__backdrop">
|
||||||
<div
|
<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"
|
class="modal"
|
||||||
>
|
>
|
||||||
<div class="modal__header">
|
<div class="modal__header">
|
||||||
|
|
@ -9,20 +13,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__body">
|
<div class="modal__body">
|
||||||
<slot />
|
<slot />
|
||||||
<div
|
<div class="modal__close-button" @click="hideModal">
|
||||||
class="modal__close-button"
|
|
||||||
@click="hideModal"
|
|
||||||
>
|
|
||||||
<cross class="modal__close-icon" />
|
<cross class="modal__close-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__footer">
|
<div class="modal__footer">
|
||||||
<slot name="footer">
|
<slot name="footer">
|
||||||
<!--<a class="button button--active">Speichern</a>-->
|
<!--<a class="button button--active">Speichern</a>-->
|
||||||
<a
|
<a class="button" @click="hideModal">Abbrechen</a>
|
||||||
class="button"
|
|
||||||
@click="hideModal"
|
|
||||||
>Abbrechen</a>
|
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -30,159 +28,158 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const Cross = () => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon');
|
const Cross = () => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
hideHeader: {
|
hideHeader: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
|
||||||
fullscreen: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
small: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
fullscreen: {
|
||||||
components: {
|
type: Boolean,
|
||||||
Cross
|
default: false,
|
||||||
},
|
},
|
||||||
|
small: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
components: {
|
||||||
hideModal() {
|
Cross,
|
||||||
this.$store.dispatch('hideModal');
|
},
|
||||||
}
|
|
||||||
}
|
methods: {
|
||||||
};
|
hideModal() {
|
||||||
|
this.$store.dispatch('hideModal');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
width: 700px;
|
width: 700px;
|
||||||
height: 80vh;
|
height: 80vh;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
|
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
|
||||||
border: 1px solid $color-silver-light;
|
border: 1px solid $color-silver-light;
|
||||||
display: -ms-grid;
|
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) {
|
@supports (display: grid) {
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
}
|
||||||
grid-template-rows: auto 1fr 65px;
|
position: fixed;
|
||||||
grid-template-areas: "header" "body" "footer";
|
top: 0;
|
||||||
-ms-grid-rows: auto 1fr 65px;
|
left: 0;
|
||||||
position: relative;
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: rgba($color-white, 0.8);
|
||||||
|
z-index: 90;
|
||||||
|
}
|
||||||
|
|
||||||
&__backdrop {
|
&__header {
|
||||||
display: flex;
|
grid-area: header;
|
||||||
justify-content: center;
|
-ms-grid-row: 1;
|
||||||
@supports (display: grid) {
|
padding: 10px $modal-lateral-padding;
|
||||||
display: grid;
|
border-bottom: 1px solid $color-silver-light;
|
||||||
}
|
}
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: rgba($color-white, 0.8);
|
|
||||||
z-index: 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
&__body {
|
||||||
grid-area: header;
|
grid-area: body;
|
||||||
-ms-grid-row: 1;
|
-ms-grid-row: 2;
|
||||||
padding: 10px $modal-lateral-padding;
|
padding: 10px $modal-lateral-padding;
|
||||||
border-bottom: 1px solid $color-silver-light;
|
overflow: auto;
|
||||||
}
|
box-sizing: border-box;
|
||||||
|
min-height: 30vh;
|
||||||
|
}
|
||||||
|
|
||||||
&__body {
|
&__close-button {
|
||||||
grid-area: body;
|
display: none;
|
||||||
-ms-grid-row: 2;
|
cursor: pointer;
|
||||||
padding: 10px $modal-lateral-padding;
|
position: absolute;
|
||||||
overflow: auto;
|
right: 15px;
|
||||||
box-sizing: border-box;
|
top: 15px;
|
||||||
min-height: 30vh;
|
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;
|
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 {
|
#{$parent}__body {
|
||||||
grid-area: footer;
|
padding: $default-padding;
|
||||||
-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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -2,40 +2,35 @@
|
||||||
<div class="modal-input">
|
<div class="modal-input">
|
||||||
<input
|
<input
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:class="{'skillbox-input--error': error}"
|
:class="{ 'skillbox-input--error': error }"
|
||||||
:value="value"
|
:value="value"
|
||||||
class="modal-input__inputfield skillbox-input"
|
class="modal-input__inputfield skillbox-input"
|
||||||
@input="$emit('input', $event.target.value)"
|
@input="$emit('input', $event.target.value)"
|
||||||
>
|
/>
|
||||||
<div
|
<div class="modal-input__error" v-if="error">Für Inhaltsblöcke muss zwingend ein Titel erfasst werden.</div>
|
||||||
class="modal-input__error"
|
|
||||||
v-if="error"
|
|
||||||
>
|
|
||||||
Für Inhaltsblöcke muss zwingend ein Titel erfasst werden.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'error', 'placeholder']
|
props: ['value', 'error', 'placeholder'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_functions.scss";
|
@import '@/styles/_functions.scss';
|
||||||
|
|
||||||
.modal-input {
|
.modal-input {
|
||||||
&__inputfield {
|
&__inputfield {
|
||||||
width: $modal-input-width;
|
width: $modal-input-width;
|
||||||
}
|
|
||||||
|
|
||||||
&__error {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: toRem(14px);
|
|
||||||
color: $color-accent-3-dark;
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__error {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: toRem(14px);
|
||||||
|
color: $color-accent-3-dark;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,59 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="more-options">
|
<div class="more-options">
|
||||||
<a
|
<a class="more-options__more-link" data-cy="more-options-link" @click.stop="showMenu = !showMenu">
|
||||||
class="more-options__more-link"
|
|
||||||
data-cy="more-options-link"
|
|
||||||
@click.stop="showMenu = !showMenu"
|
|
||||||
>
|
|
||||||
<ellipses class="more-options__ellipses" />
|
<ellipses class="more-options__ellipses" />
|
||||||
</a>
|
</a>
|
||||||
<widget-popover
|
<widget-popover class="more-options__popover" v-if="showMenu" @hide-me="showMenu = false">
|
||||||
class="more-options__popover"
|
|
||||||
v-if="showMenu"
|
|
||||||
@hide-me="showMenu = false"
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</widget-popover>
|
</widget-popover>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||||
|
|
||||||
const Ellipses = () => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses.vue');
|
const Ellipses = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Ellipses.vue');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
WidgetPopover,
|
WidgetPopover,
|
||||||
Ellipses
|
Ellipses,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showMenu: false
|
showMenu: false,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.more-options {
|
.more-options {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
&__ellipses {
|
&__ellipses {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
fill: $color-charcoal-dark;
|
fill: $color-charcoal-dark;
|
||||||
margin-top: -7px;
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<base-input
|
<base-input :label="label" :checked="checked" :item="item" :type="'radiobutton'" @input="passOn" />
|
||||||
:label="label"
|
|
||||||
:checked="checked"
|
|
||||||
:item="item"
|
|
||||||
:type="'radiobutton'"
|
|
||||||
@input="passOn"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseInput from '@/components/ui/BaseInput';
|
import BaseInput from '@/components/ui/BaseInput';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
label: String,
|
label: String,
|
||||||
checked: {
|
checked: {
|
||||||
type: Boolean
|
type: Boolean,
|
||||||
},
|
|
||||||
item: Object
|
|
||||||
},
|
},
|
||||||
|
item: Object,
|
||||||
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
BaseInput
|
BaseInput,
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
passOn() {
|
||||||
|
this.$emit('input', ...arguments);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
methods: {
|
};
|
||||||
passOn() {
|
|
||||||
this.$emit('input', ...arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="read-only-banner" data-cy="read-only-banner" v-if="me.readOnly || me.selectedClass.readOnly">
|
||||||
class="read-only-banner"
|
|
||||||
data-cy="read-only-banner"
|
|
||||||
v-if="me.readOnly || me.selectedClass.readOnly"
|
|
||||||
>
|
|
||||||
<div class="read-only-banner__content">
|
<div class="read-only-banner__content">
|
||||||
<p class="read-only-banner__text">
|
<p class="read-only-banner__text">{{ readOnlyText }} Sie können Inhalte lesen, aber nicht bearbeiten.</p>
|
||||||
{{ readOnlyText }} Sie können Inhalte lesen, aber nicht
|
|
||||||
bearbeiten.
|
|
||||||
</p>
|
|
||||||
<div class="read-only-banner__buttons">
|
<div class="read-only-banner__buttons">
|
||||||
<router-link
|
<router-link
|
||||||
:to="licenseActivationLink"
|
:to="licenseActivationLink"
|
||||||
|
|
@ -18,96 +11,93 @@
|
||||||
>
|
>
|
||||||
Neuen Lizenzcode eingeben
|
Neuen Lizenzcode eingeben
|
||||||
</router-link>
|
</router-link>
|
||||||
<a
|
<a target="_blank" href="https://myskillbox.ch/lesemodus" class="button button--secondary"
|
||||||
target="_blank"
|
>Mehr Informationen zum Lesemodus</a
|
||||||
href="https://myskillbox.ch/lesemodus"
|
>
|
||||||
class="button button--secondary"
|
|
||||||
>Mehr Informationen zum Lesemodus</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import {LICENSE_ACTIVATION} from '@/router/auth.names';
|
import { LICENSE_ACTIVATION } from '@/router/auth.names';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
me: {
|
|
||||||
readOnly: false,
|
|
||||||
selectedClass: {
|
|
||||||
readOnly: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
licenseActivationLink: {
|
|
||||||
name: LICENSE_ACTIVATION,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
apollo: {
|
|
||||||
me: {
|
me: {
|
||||||
query: gql`
|
readOnly: false,
|
||||||
|
selectedClass: {
|
||||||
|
readOnly: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
licenseActivationLink: {
|
||||||
|
name: LICENSE_ACTIVATION,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
me: {
|
||||||
|
query: gql`
|
||||||
query {
|
query {
|
||||||
me {
|
me {
|
||||||
readOnly
|
readOnly
|
||||||
selectedClass {
|
selectedClass {
|
||||||
readOnly
|
readOnly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
fetchPolicy: 'cache-only',
|
fetchPolicy: 'cache-only',
|
||||||
update({me}) {
|
update({ me }) {
|
||||||
if (!me) {
|
if (!me) {
|
||||||
return {
|
return {
|
||||||
|
readOnly: false,
|
||||||
|
selectedClass: {
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
selectedClass: {
|
},
|
||||||
readOnly: false,
|
};
|
||||||
},
|
}
|
||||||
};
|
return me;
|
||||||
}
|
|
||||||
return me;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
readOnlyText() {
|
readOnlyText() {
|
||||||
return this.me.readOnly ? 'Sie besitzen keine aktive Lizenz.' : 'Sie sind in dieser Klasse nicht mehr aktiv.';
|
return this.me.readOnly ? 'Sie besitzen keine aktive Lizenz.' : 'Sie sind in dieser Klasse nicht mehr aktiv.';
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.read-only-banner {
|
.read-only-banner {
|
||||||
background-color: $color-brand-light;
|
background-color: $color-brand-light;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: $small-spacing 0;
|
padding: $small-spacing 0;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
max-width: $screen-width;
|
max-width: $screen-width;
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
padding: 0;
|
|
||||||
@include regular-text;
|
|
||||||
margin-bottom: $small-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
@include default-link;
|
|
||||||
margin-right: $small-spacing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
padding: 0;
|
||||||
|
@include regular-text;
|
||||||
|
margin-bottom: $small-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttons {
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
@include default-link;
|
||||||
|
margin-right: $small-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,78 +1,73 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<a
|
<a class="scroll-up" v-if="scroll > 200" @click="scrollTop">
|
||||||
class="scroll-up"
|
|
||||||
v-if="scroll>200"
|
|
||||||
@click="scrollTop"
|
|
||||||
>
|
|
||||||
<arrow-up class="scroll-up__icon" />
|
<arrow-up class="scroll-up__icon" />
|
||||||
</a>
|
</a>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const ArrowUp = () => import(/* webpackChunkName: "icons" */'@/components/icons/ArrowUp');
|
const ArrowUp = () => import(/* webpackChunkName: "icons" */ '@/components/icons/ArrowUp');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ArrowUp
|
ArrowUp,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scroll: 0
|
scroll: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
let html = document.scrollingElement;
|
let html = document.scrollingElement;
|
||||||
document.body.onscroll = () => {
|
document.body.onscroll = () => {
|
||||||
this.scroll = html.scrollTop;
|
this.scroll = html.scrollTop;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
document.body.onscroll = null;
|
document.body.onscroll = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
scrollTop() {
|
scrollTop() {
|
||||||
document.scrollingElement.scrollTop = 0;
|
document.scrollingElement.scrollTop = 0;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '@/styles/_variables.scss';
|
@import '@/styles/_variables.scss';
|
||||||
@import '@/styles/_mixins.scss';
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.scroll-up {
|
.scroll-up {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: $large-spacing;
|
right: $large-spacing;
|
||||||
bottom: $large-spacing;
|
bottom: $large-spacing;
|
||||||
padding: $medium-spacing;
|
padding: $medium-spacing;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
@include default-box-shadow;
|
@include default-box-shadow;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
border: 1px solid $color-silver;
|
border: 1px solid $color-silver;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
&__icon {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
fill: $color-brand;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
fill: $color-brand;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fade-enter-active, .fade-leave-active {
|
.fade-enter-active,
|
||||||
transition: opacity .3s;
|
.fade-leave-active {
|
||||||
}
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */
|
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||||
{
|
opacity: 0;
|
||||||
opacity: 0;
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="section-block">
|
<div class="section-block">
|
||||||
<div
|
<div :class="{ 'section-block--navigatable': route }" class="section-block__illustration" @click="navigate()">
|
||||||
:class="{'section-block--navigatable': route}"
|
|
||||||
class="section-block__illustration"
|
|
||||||
@click="navigate()"
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div :class="{ 'section-block--navigatable': route }" class="section-block__title block-title" @click="navigate()">
|
||||||
:class="{'section-block--navigatable': route}"
|
|
||||||
class="section-block__title block-title"
|
|
||||||
@click="navigate()"
|
|
||||||
>
|
|
||||||
<h2 class="block-title__title">
|
<h2 class="block-title__title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -23,91 +15,88 @@
|
||||||
<div class="section-block__content section-content">
|
<div class="section-block__content section-content">
|
||||||
<div class="section-content__subsection subsection">
|
<div class="section-content__subsection subsection">
|
||||||
<a
|
<a
|
||||||
:class="{'section-block--navigatable': route}"
|
:class="{ 'section-block--navigatable': route }"
|
||||||
class="subsection__content button button--primary"
|
class="subsection__content button button--primary"
|
||||||
v-if="route"
|
v-if="route"
|
||||||
@click="navigate()"
|
@click="navigate()"
|
||||||
>
|
>
|
||||||
{{ linkText }}
|
{{ linkText }}
|
||||||
</a>
|
</a>
|
||||||
<span
|
<span class="subsection__content subsection__content--disabled" v-if="!route">Noch nicht verfügbar</span>
|
||||||
class="subsection__content subsection__content--disabled"
|
|
||||||
v-if="!route"
|
|
||||||
>Noch nicht verfügbar</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['title', 'subtitle', 'route', 'linkText'],
|
props: ['title', 'subtitle', 'route', 'linkText'],
|
||||||
methods: {
|
methods: {
|
||||||
navigate() {
|
navigate() {
|
||||||
if (this.route) {
|
if (this.route) {
|
||||||
this.$router.push(this.route);
|
this.$router.push(this.route);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_functions.scss";
|
@import '@/styles/_functions.scss';
|
||||||
|
|
||||||
.section-block {
|
.section-block {
|
||||||
border-radius: $default-border-radius;
|
border-radius: $default-border-radius;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&--navigatable {
|
&--navigatable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.block-title {
|
&__title {
|
||||||
&__title, &__subtitle {
|
padding: 20px;
|
||||||
color: $color-charcoal-dark;
|
}
|
||||||
font-family: $sans-serif-font-family;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
.block-title {
|
||||||
font-size: toRem(29px);
|
&__title,
|
||||||
text-transform: uppercase;
|
&__subtitle {
|
||||||
margin-bottom: 8px;
|
color: $color-charcoal-dark;
|
||||||
font-weight: 600;
|
font-family: $sans-serif-font-family;
|
||||||
}
|
|
||||||
|
|
||||||
&__subtitle {
|
|
||||||
font-size: toRem(14px);
|
|
||||||
font-weight: $font-weight-regular;
|
|
||||||
min-height: 2rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-content {
|
&__title {
|
||||||
padding: 15px 15px 15px;
|
font-size: toRem(29px);
|
||||||
|
text-transform: uppercase;
|
||||||
&__subsection {
|
margin-bottom: 8px;
|
||||||
padding-bottom: 15px;
|
font-weight: 600;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.subsection {
|
&__subtitle {
|
||||||
&__content {
|
font-size: toRem(14px);
|
||||||
font-family: $sans-serif-font-family;
|
font-weight: $font-weight-regular;
|
||||||
font-weight: 600;
|
min-height: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&--disabled {
|
.section-content {
|
||||||
color: $color-silver-dark;
|
padding: 15px 15px 15px;
|
||||||
}
|
|
||||||
|
&__subsection {
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subsection {
|
||||||
|
&__content {
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: $color-silver-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="student-submission__entry entry">
|
<div class="student-submission__entry entry">
|
||||||
<p>{{ submission.text | trimToLength(50) }}</p>
|
<p>{{ submission.text | trimToLength(50) }}</p>
|
||||||
<p
|
<p class="entry__document" v-if="submission.document && submission.document.length > 0">
|
||||||
class="entry__document"
|
<student-submission-document :document="submission.document" class="entry-document" />
|
||||||
v-if="submission.document && submission.document.length > 0"
|
|
||||||
>
|
|
||||||
<student-submission-document
|
|
||||||
:document="submission.document"
|
|
||||||
class="entry-document"
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="student-submission__feedback entry" v-if="submission.submissionFeedback">
|
||||||
class="student-submission__feedback entry"
|
<p :class="{ 'entry__text--final': submission.submissionFeedback.final }" class="entry__text">
|
||||||
v-if="submission.submissionFeedback"
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
:class="{'entry__text--final': submission.submissionFeedback.final}"
|
|
||||||
class="entry__text"
|
|
||||||
>
|
|
||||||
{{ submission.submissionFeedback.text | trimToLength(50) }}
|
{{ submission.submissionFeedback.text | trimToLength(50) }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -30,66 +18,67 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import StudentSubmissionDocument from '@/components/StudentSubmissionDocument';
|
import StudentSubmissionDocument from '@/components/StudentSubmissionDocument';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['submission'],
|
props: ['submission'],
|
||||||
components: {
|
components: {
|
||||||
StudentSubmissionDocument
|
StudentSubmissionDocument,
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
trimToLength: function(text, numberOfChars) {
|
trimToLength: function (text, numberOfChars) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
if (text.length <= numberOfChars) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
const index = text.indexOf(' ', numberOfChars - 1);
|
|
||||||
if (index === -1) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
return `${text.substring(0, index)}…`;
|
|
||||||
}
|
}
|
||||||
|
if (text.length <= numberOfChars) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
const index = text.indexOf(' ', numberOfChars - 1);
|
||||||
|
if (index === -1) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return `${text.substring(0, index)}…`;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
name() {
|
name() {
|
||||||
return this.submission && this.submission.student
|
return this.submission && this.submission.student
|
||||||
? `${this.submission.student.firstName} ${this.submission.student.lastName}` : '';
|
? `${this.submission.student.firstName} ${this.submission.student.lastName}`
|
||||||
},
|
: '';
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.student-submission {
|
.student-submission {
|
||||||
@include table-row;
|
@include table-row;
|
||||||
|
|
||||||
&__student-name {
|
&__student-name {
|
||||||
font-size: toRem(17px);
|
font-size: toRem(17px);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-family: $sans-serif-font-family;
|
font-family: $sans-serif-font-family;
|
||||||
}
|
|
||||||
|
|
||||||
&__entry {
|
|
||||||
font-size: toRem(14px);
|
|
||||||
font-family: $sans-serif-font-family;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry-document {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry {
|
&__entry {
|
||||||
&__text {
|
font-size: toRem(14px);
|
||||||
color: $color-silver-dark;
|
font-family: $sans-serif-font-family;
|
||||||
&--final {
|
}
|
||||||
color: $color-charcoal-dark;
|
|
||||||
}
|
.entry-document {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry {
|
||||||
|
&__text {
|
||||||
|
color: $color-silver-dark;
|
||||||
|
&--final {
|
||||||
|
color: $color-charcoal-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="submission-document">
|
<div class="submission-document">
|
||||||
<p
|
<p class="submission-document__content content" v-if="document && document.length > 0">
|
||||||
class="submission-document__content content"
|
|
||||||
v-if="document && document.length > 0"
|
|
||||||
>
|
|
||||||
<document-icon class="content__icon" /><span class="content__text">{{ filename }}</span>
|
<document-icon class="content__icon" /><span class="content__text">{{ filename }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import filenameFromUrl from '@/helpers/urls';
|
||||||
|
const DocumentIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon');
|
||||||
|
|
||||||
import filenameFromUrl from '@/helpers/urls';
|
export default {
|
||||||
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
|
name: 'StudentSubmissionDocument',
|
||||||
|
props: ['document'],
|
||||||
|
components: { DocumentIcon },
|
||||||
|
|
||||||
export default {
|
computed: {
|
||||||
name: 'StudentSubmissionDocument',
|
filename() {
|
||||||
props: ['document'],
|
return filenameFromUrl(this.document);
|
||||||
components: { DocumentIcon },
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
filename() {
|
|
||||||
return filenameFromUrl(this.document);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
align-self: center;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
align-self: center;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -4,53 +4,50 @@
|
||||||
<avatar :avatar-url="avatarUrl" />
|
<avatar :avatar-url="avatarUrl" />
|
||||||
</div>
|
</div>
|
||||||
<span class="user-widget__name">{{ firstName }} {{ lastName }}</span>
|
<span class="user-widget__name">{{ firstName }} {{ lastName }}</span>
|
||||||
<span
|
<span class="user-widget__date" v-if="date">{{ date }}</span>
|
||||||
class="user-widget__date"
|
|
||||||
v-if="date"
|
|
||||||
>{{ date }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Avatar from '@/components/profile/Avatar';
|
import Avatar from '@/components/profile/Avatar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['firstName', 'lastName', 'avatarUrl', 'date'],
|
props: ['firstName', 'lastName', 'avatarUrl', 'date'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Avatar
|
Avatar,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.user-widget {
|
.user-widget {
|
||||||
|
color: $color-silver-dark;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
padding: 0px 10px;
|
||||||
color: $color-silver-dark;
|
color: $color-silver-dark;
|
||||||
display: flex;
|
font-family: $sans-serif-font-family;
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
&__name {
|
&__date {
|
||||||
padding: 0px 10px;
|
font-family: $sans-serif-font-family;
|
||||||
color: $color-silver-dark;
|
}
|
||||||
font-family: $sans-serif-font-family;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__date {
|
&__avatar {
|
||||||
font-family: $sans-serif-font-family;
|
width: 30px;
|
||||||
}
|
height: 30px;
|
||||||
|
fill: $color-silver-dark;
|
||||||
|
}
|
||||||
|
|
||||||
&__avatar {
|
&--is-profile {
|
||||||
width: 30px;
|
& > span {
|
||||||
height: 30px;
|
color: $color-brand;
|
||||||
fill: $color-silver-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--is-profile {
|
|
||||||
& > span {
|
|
||||||
color: $color-brand;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,70 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="{ 'user-widget--is-profile': isProfile }" class="user-widget">
|
||||||
:class="{'user-widget--is-profile': isProfile}"
|
<div class="user-widget__avatar" data-cy="user-widget-avatar">
|
||||||
class="user-widget"
|
<avatar :avatar-url="avatarUrl" :icon-highlighted="isProfile" />
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="user-widget__avatar"
|
|
||||||
data-cy="user-widget-avatar"
|
|
||||||
>
|
|
||||||
<avatar
|
|
||||||
:avatar-url="avatarUrl"
|
|
||||||
:icon-highlighted="isProfile"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Avatar from '@/components/profile/Avatar';
|
import Avatar from '@/components/profile/Avatar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
avatarUrl: {
|
avatarUrl: {
|
||||||
type: String
|
type: String,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Avatar
|
Avatar,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isProfile() {
|
||||||
|
return this.$route.meta.isProfile;
|
||||||
},
|
},
|
||||||
computed: {
|
},
|
||||||
isProfile() {
|
};
|
||||||
return this.$route.meta.isProfile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<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;
|
color: $color-silver-dark;
|
||||||
display: flex;
|
font-family: $sans-serif-font-family;
|
||||||
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 {
|
&__date {
|
||||||
top: 40px;
|
font-family: $sans-serif-font-family;
|
||||||
white-space: nowrap;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
&__avatar {
|
||||||
padding: 0px $small-spacing;
|
width: 30px;
|
||||||
color: $color-silver-dark;
|
height: 30px;
|
||||||
font-family: $sans-serif-font-family;
|
fill: $color-silver-dark;
|
||||||
}
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
&__date {
|
&--is-profile {
|
||||||
font-family: $sans-serif-font-family;
|
& > span {
|
||||||
}
|
color: $color-brand;
|
||||||
|
|
||||||
&__avatar {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
fill: $color-silver-dark;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--is-profile {
|
|
||||||
& > span {
|
|
||||||
color: $color-brand;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<nav
|
<nav :class="{ 'content-navigation--sidebar': isSidebar }" class="content-navigation">
|
||||||
:class="{'content-navigation--sidebar': isSidebar}"
|
|
||||||
class="content-navigation"
|
|
||||||
>
|
|
||||||
<div class="content-navigation__primary">
|
<div class="content-navigation__primary">
|
||||||
<div class="content-navigation__item">
|
<div class="content-navigation__item">
|
||||||
<router-link
|
<router-link
|
||||||
:class="{'content-navigation__link--active': isActive('book')}"
|
:class="{ 'content-navigation__link--active': isActive('book') }"
|
||||||
:to="topicRoute"
|
:to="topicRoute"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
|
|
@ -15,9 +12,7 @@
|
||||||
{{ $flavor.textTopics }}
|
{{ $flavor.textTopics }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<topic-navigation
|
<topic-navigation v-if="isSidebar" />
|
||||||
v-if="isSidebar"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-navigation__item">
|
<div class="content-navigation__item">
|
||||||
|
|
@ -33,7 +28,7 @@
|
||||||
|
|
||||||
<div class="content-navigation__item">
|
<div class="content-navigation__item">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'news'}"
|
:to="{ name: 'news' }"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
data-cy="news-navigation-link"
|
data-cy="news-navigation-link"
|
||||||
|
|
@ -45,19 +40,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-link
|
<router-link to="/" class="content-navigation__logo" data-cy="home-link" v-if="!isSidebar">
|
||||||
to="/"
|
|
||||||
class="content-navigation__logo"
|
|
||||||
data-cy="home-link"
|
|
||||||
v-if="!isSidebar"
|
|
||||||
>
|
|
||||||
<logo class="content-navigation__logo-icon" />
|
<logo class="content-navigation__logo-icon" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<div class="content-navigation__secondary">
|
<div class="content-navigation__secondary">
|
||||||
<div class="content-navigation__item content-navigation__item--secondary">
|
<div class="content-navigation__item content-navigation__item--secondary">
|
||||||
<router-link
|
<router-link
|
||||||
:class="{'content-navigation__link--active': isRoomUrl()}"
|
:class="{ 'content-navigation__link--active': isRoomUrl() }"
|
||||||
to="/rooms"
|
to="/rooms"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
|
|
@ -67,10 +57,7 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="content-navigation__item content-navigation__item--secondary" v-if="showPortfolio">
|
||||||
class="content-navigation__item content-navigation__item--secondary"
|
|
||||||
v-if="showPortfolio"
|
|
||||||
>
|
|
||||||
<router-link
|
<router-link
|
||||||
to="/portfolio"
|
to="/portfolio"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
|
|
@ -80,16 +67,13 @@
|
||||||
Portfolio
|
Portfolio
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="content-navigation__item content-navigation__item--secondary" v-if="isSidebar">
|
||||||
class="content-navigation__item content-navigation__item--secondary"
|
|
||||||
v-if="isSidebar"
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
:href="$flavor.supportLink"
|
:href="$flavor.supportLink"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
@click="close"
|
@click="close"
|
||||||
>Support
|
>Support
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -97,141 +81,142 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
||||||
|
|
||||||
import sidebarMixin from '@/mixins/sidebar';
|
import sidebarMixin from '@/mixins/sidebar';
|
||||||
import meMixin from '@/mixins/me';
|
import meMixin from '@/mixins/me';
|
||||||
|
|
||||||
const Logo = () => import(/* webpackChunkName: "icons" */'@/components/icons/Logo');
|
const Logo = () => import(/* webpackChunkName: "icons" */ '@/components/icons/Logo');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
isSidebar: {
|
isSidebar: {
|
||||||
default: false
|
default: false,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mixins: [sidebarMixin, meMixin],
|
mixins: [sidebarMixin, meMixin],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
TopicNavigation,
|
TopicNavigation,
|
||||||
Logo
|
Logo,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
showPortfolio() {
|
||||||
|
return this.$flavor.showPortfolio;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
methods: {
|
||||||
showPortfolio() {
|
isActive(linkName) {
|
||||||
return this.$flavor.showPortfolio;
|
return linkName === 'book' && this.$route.path.indexOf('module') > -1;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
isRoomUrl() {
|
||||||
methods: {
|
return this.$route.path.indexOf('room') > -1;
|
||||||
isActive(linkName) {
|
},
|
||||||
return linkName === 'book' && this.$route.path.indexOf('module') > -1;
|
close() {
|
||||||
},
|
this.closeSidebar('navigation');
|
||||||
isRoomUrl() {
|
},
|
||||||
return this.$route.path.indexOf('room') > -1;
|
},
|
||||||
},
|
};
|
||||||
close() {
|
|
||||||
this.closeSidebar('navigation');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.content-navigation {
|
.content-navigation {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__link {
|
&__link {
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
@include navigation-link;
|
@include navigation-link;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__primary, &__secondary {
|
&__primary,
|
||||||
display: none;
|
&__secondary {
|
||||||
flex-direction: row;
|
display: none;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__logo {
|
|
||||||
color: #17A887;
|
|
||||||
font-size: 36px;
|
|
||||||
font-weight: 800;
|
|
||||||
font-family: $sans-serif-font-family;
|
|
||||||
display: flex;
|
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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="slide">
|
<transition name="slide">
|
||||||
<div
|
<div class="navigation-sidebar" v-if="sidebar.navigation" v-click-outside="close">
|
||||||
class="navigation-sidebar"
|
<content-navigation :is-sidebar="true" class="navigation-sidebar__main" />
|
||||||
v-if="sidebar.navigation"
|
<div class="navigation-sidebar__close-button" @click="close">
|
||||||
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" />
|
<cross class="navigation-sidebar__close-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -20,93 +10,94 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation';
|
import ContentNavigation from '@/components/book-navigation/ContentNavigation';
|
||||||
|
|
||||||
import sidebarMixin from '@/mixins/sidebar';
|
import sidebarMixin from '@/mixins/sidebar';
|
||||||
|
|
||||||
const Cross = () => import(/* webpackChunkName: "icons" */'@/components/icons/CrossIcon');
|
const Cross = () => import(/* webpackChunkName: "icons" */ '@/components/icons/CrossIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [sidebarMixin],
|
mixins: [sidebarMixin],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ContentNavigation,
|
ContentNavigation,
|
||||||
Cross
|
Cross,
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.closeSidebar('navigation');
|
||||||
},
|
},
|
||||||
|
},
|
||||||
methods: {
|
};
|
||||||
close() {
|
|
||||||
this.closeSidebar('navigation');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
$desktop-width: 285px;
|
$desktop-width: 285px;
|
||||||
|
|
||||||
.navigation-sidebar {
|
.navigation-sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
box-shadow: 0px 2px 9px rgba(0, 0, 0, 0.12);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide {
|
display: grid;
|
||||||
&-enter-active, &-leave-active {
|
|
||||||
transition: left 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter, &-leave-to {
|
grid-template-columns: 1fr 50px;
|
||||||
left: -100vw;
|
grid-template-rows: 50px max-content auto 100px;
|
||||||
@include desktop {
|
|
||||||
left: -$desktop-width;
|
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,
|
||||||
|
&-leave-to {
|
||||||
|
left: -100vw;
|
||||||
|
@include desktop {
|
||||||
|
left: -$desktop-width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,44 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="{ 'sub-navigation-item--active': show }" class="sub-navigation-item" v-click-outside="close">
|
||||||
:class="{ 'sub-navigation-item--active': show}"
|
<div class="sub-navigation-item__title" @click="show = !show">
|
||||||
class="sub-navigation-item"
|
|
||||||
v-click-outside="close"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="sub-navigation-item__title"
|
|
||||||
@click="show = !show"
|
|
||||||
>
|
|
||||||
{{ title }}
|
{{ title }}
|
||||||
<chevron-down class="sub-navigation-item__icon sub-navigation-item__chevron-down" />
|
<chevron-down class="sub-navigation-item__icon sub-navigation-item__chevron-down" />
|
||||||
<chevron-up class="sub-navigation-item__icon sub-navigation-item__chevron-up" />
|
<chevron-up class="sub-navigation-item__icon sub-navigation-item__chevron-up" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="sub-navigation-item__nav-items book-subnavigation" v-if="show">
|
||||||
class="sub-navigation-item__nav-items book-subnavigation"
|
|
||||||
v-if="show"
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const ChevronDown = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronDown');
|
const ChevronDown = () => import(/* webpackChunkName: "icons" */ '@/components/icons/ChevronDown');
|
||||||
const ChevronUp = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronUp');
|
const ChevronUp = () => import(/* webpackChunkName: "icons" */ '@/components/icons/ChevronUp');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['title'],
|
props: ['title'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronUp
|
ChevronUp,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.show = false;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
methods: {
|
||||||
return {
|
close() {
|
||||||
show: false
|
this.show = false;
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
watch: {
|
};
|
||||||
$route() {
|
|
||||||
this.show = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
this.show = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<nav class="topic-navigation">
|
<nav class="topic-navigation">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'topic', params: {topicSlug: topic.slug}}"
|
:to="{ name: 'topic', params: { topicSlug: topic.slug } }"
|
||||||
:class="{'topic-navigation__topic--active': topic.active, 'book-subnavigation__item--mobile': mobile}"
|
:class="{ 'topic-navigation__topic--active': topic.active, 'book-subnavigation__item--mobile': mobile }"
|
||||||
tag="div"
|
tag="div"
|
||||||
active-class="book-subnavigation__item--active"
|
active-class="book-subnavigation__item--active"
|
||||||
class="topic-navigation__topic book-subnavigation__item"
|
class="topic-navigation__topic book-subnavigation__item"
|
||||||
|
|
@ -17,49 +17,49 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ALL_TOPICS_QUERY from '@/graphql/gql/queries/allTopicsQuery.gql';
|
import ALL_TOPICS_QUERY from '@/graphql/gql/queries/allTopicsQuery.gql';
|
||||||
import sidebarMixin from '@/mixins/sidebar';
|
import sidebarMixin from '@/mixins/sidebar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
mobile: {
|
mobile: {
|
||||||
default: false
|
default: false,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mixins: [sidebarMixin],
|
mixins: [sidebarMixin],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
topics: []
|
topics: [],
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
topicId(id) {
|
||||||
|
return atob(id);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
apollo: {
|
||||||
topicId(id) {
|
topics: {
|
||||||
return atob(id);
|
query: ALL_TOPICS_QUERY,
|
||||||
}
|
manual: true,
|
||||||
},
|
result({ data, loading }) {
|
||||||
|
if (!loading) {
|
||||||
apollo: {
|
this.topics = this.$getRidOfEdges(data).topics;
|
||||||
topics: {
|
|
||||||
query: ALL_TOPICS_QUERY,
|
|
||||||
manual: true,
|
|
||||||
result({data, loading}) {
|
|
||||||
if (!loading) {
|
|
||||||
this.topics = this.$getRidOfEdges(data).topics;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.topic-navigation {
|
.topic-navigation {
|
||||||
&__topic {
|
&__topic {
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,37 @@
|
||||||
<template>
|
<template>
|
||||||
<a
|
<a class="add-content-link" data-cy="add-content-link" @click="$emit('click')"
|
||||||
class="add-content-link"
|
><plus-icon class="add-content-link__icon" /> <span class="add-content-link__text">Inhalt hinzufügen</span></a
|
||||||
data-cy="add-content-link"
|
>
|
||||||
@click="$emit('click')"
|
|
||||||
><plus-icon class="add-content-link__icon" /> <span class="add-content-link__text">Inhalt hinzufügen</span></a>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PlusIcon from '@/components/icons/PlusIcon';
|
import PlusIcon from '@/components/icons/PlusIcon';
|
||||||
export default {
|
export default {
|
||||||
components: { PlusIcon }
|
components: { PlusIcon },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
$color: $color-silver-dark;
|
$color: $color-silver-dark;
|
||||||
$icon-size: 14px;
|
$icon-size: 14px;
|
||||||
|
|
||||||
.add-content-link {
|
.add-content-link {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: $icon-size;
|
width: $icon-size;
|
||||||
height: $icon-size;
|
height: $icon-size;
|
||||||
margin-right: $small-spacing;
|
margin-right: $small-spacing;
|
||||||
fill: $color;
|
fill: $color;
|
||||||
}
|
}
|
||||||
&__text {
|
&__text {
|
||||||
// custom style, because the view needs this
|
// custom style, because the view needs this
|
||||||
@include large-link;
|
@include large-link;
|
||||||
color: $color;
|
color: $color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content-block-form content-list__parent">
|
<div class="content-block-form content-list__parent">
|
||||||
<div class="content-block-form__content">
|
<div class="content-block-form__content">
|
||||||
<h1
|
<h1 class="heading-1 content-block-form__heading" data-cy="content-block-form-heading">
|
||||||
class="heading-1 content-block-form__heading"
|
|
||||||
data-cy="content-block-form-heading"
|
|
||||||
>
|
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
|
@ -15,26 +12,21 @@
|
||||||
class="content-block-form__task-toggle"
|
class="content-block-form__task-toggle"
|
||||||
label="Inhaltsblock als Auftrag formatieren"
|
label="Inhaltsblock als Auftrag formatieren"
|
||||||
v-if="hasDefaultFeatures"
|
v-if="hasDefaultFeatures"
|
||||||
@input="localContentBlock.isAssignment=$event"
|
@input="localContentBlock.isAssignment = $event"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Form for title of content block -->
|
<!-- Form for title of content block -->
|
||||||
<content-form-section
|
<content-form-section data-cy="content-form-title-section" title="Titel (Pflichtfeld)">
|
||||||
data-cy="content-form-title-section"
|
|
||||||
title="Titel (Pflichtfeld)"
|
|
||||||
>
|
|
||||||
<input-with-label
|
<input-with-label
|
||||||
:value="localContentBlock.title"
|
:value="localContentBlock.title"
|
||||||
data-cy="content-block-title"
|
data-cy="content-block-title"
|
||||||
placeholder="z.B. Auftrag 3"
|
placeholder="z.B. Auftrag 3"
|
||||||
@input="localContentBlock.title=$event"
|
@input="localContentBlock.title = $event"
|
||||||
/>
|
/>
|
||||||
</content-form-section>
|
</content-form-section>
|
||||||
|
|
||||||
<!-- Add content at top of content block -->
|
<!-- Add content at top of content block -->
|
||||||
<add-content-link
|
<add-content-link @click="addBlock(-1)" />
|
||||||
@click="addBlock(-1)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Loop for outer contents layer -->
|
<!-- Loop for outer contents layer -->
|
||||||
<div
|
<div
|
||||||
|
|
@ -43,32 +35,21 @@
|
||||||
:key="block.id"
|
:key="block.id"
|
||||||
>
|
>
|
||||||
<!-- If the block is a content list -->
|
<!-- If the block is a content list -->
|
||||||
<div
|
<div class="content-block-form__segment" data-cy="content-list" v-if="block.type === 'content_list_item'">
|
||||||
class="content-block-form__segment"
|
|
||||||
data-cy="content-list"
|
|
||||||
v-if="block.type === 'content_list_item'"
|
|
||||||
>
|
|
||||||
<content-element-actions
|
<content-element-actions
|
||||||
class="content-block-form__actions"
|
class="content-block-form__actions"
|
||||||
:actions="{extended: true, up: outer>0, down: outer<localContentBlock.contents.length }"
|
:actions="{ extended: true, up: outer > 0, down: outer < localContentBlock.contents.length }"
|
||||||
@remove="remove(outer)"
|
@remove="remove(outer)"
|
||||||
@move-up="up(outer)"
|
@move-up="up(outer)"
|
||||||
@move-down="down(outer)"
|
@move-down="down(outer)"
|
||||||
@move-top="top(outer)"
|
@move-top="top(outer)"
|
||||||
@move-bottom="bottom(outer)"
|
@move-bottom="bottom(outer)"
|
||||||
/>
|
/>
|
||||||
<ol
|
<ol class="content-list__item" data-cy="content-list-item">
|
||||||
class="content-list__item"
|
<li class="content-block-form__segment" v-for="(content, index) in block.contents" :key="content.id">
|
||||||
data-cy="content-list-item"
|
|
||||||
>
|
|
||||||
<li
|
|
||||||
class="content-block-form__segment"
|
|
||||||
v-for="(content, index) in block.contents"
|
|
||||||
:key="content.id"
|
|
||||||
>
|
|
||||||
<content-element
|
<content-element
|
||||||
:first-element="index===0"
|
:first-element="index === 0"
|
||||||
:last-element="index===block.contents.length-1"
|
:last-element="index === block.contents.length - 1"
|
||||||
:element="content"
|
:element="content"
|
||||||
class="content-block-form__segment"
|
class="content-block-form__segment"
|
||||||
:top-level="false"
|
:top-level="false"
|
||||||
|
|
@ -80,10 +61,7 @@
|
||||||
@bottom="bottom(outer, index)"
|
@bottom="bottom(outer, index)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<add-content-link
|
<add-content-link class="content-block-form__add-button" @click="addBlock(outer, index)" />
|
||||||
class="content-block-form__add-button"
|
|
||||||
@click="addBlock(outer, index)"
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -93,8 +71,8 @@
|
||||||
:element="block"
|
:element="block"
|
||||||
class="content-block-form__segment"
|
class="content-block-form__segment"
|
||||||
:top-level="true"
|
:top-level="true"
|
||||||
:first-element="outer===0"
|
:first-element="outer === 0"
|
||||||
:last-element="outer===localContentBlock.contents.length-1"
|
:last-element="outer === localContentBlock.contents.length - 1"
|
||||||
v-else
|
v-else
|
||||||
@update="update(outer, $event)"
|
@update="update(outer, $event)"
|
||||||
@remove="remove(outer, undefined, $event)"
|
@remove="remove(outer, undefined, $event)"
|
||||||
|
|
@ -105,11 +83,10 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Add element after the looped item -->
|
<!-- Add element after the looped item -->
|
||||||
<add-content-link
|
<add-content-link @click="addBlock(outer)" />
|
||||||
@click="addBlock(outer)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div><!-- -->
|
</div>
|
||||||
|
<!-- -->
|
||||||
<!-- Save and Cancel buttons -->
|
<!-- Save and Cancel buttons -->
|
||||||
<footer class="content-block-form__footer">
|
<footer class="content-block-form__footer">
|
||||||
<div class="content-block-form__buttons">
|
<div class="content-block-form__buttons">
|
||||||
|
|
@ -121,309 +98,307 @@
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a class="button" @click="$emit('back')">Abbrechen</a>
|
||||||
class="button"
|
|
||||||
@click="$emit('back')"
|
|
||||||
>Abbrechen</a>
|
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue, {PropType} from 'vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import Toggle from '@/components/ui/Toggle.vue';
|
import Toggle from '@/components/ui/Toggle.vue';
|
||||||
import ContentFormSection from '@/components/content-block-form/ContentFormSection.vue';
|
import ContentFormSection from '@/components/content-block-form/ContentFormSection.vue';
|
||||||
import InputWithLabel from '@/components/ui/InputWithLabel.vue';
|
import InputWithLabel from '@/components/ui/InputWithLabel.vue';
|
||||||
import AddContentLink from '@/components/content-block-form/AddContentLink.vue';
|
import AddContentLink from '@/components/content-block-form/AddContentLink.vue';
|
||||||
|
|
||||||
import ContentElement from '@/components/content-block-form/ContentElement.vue';
|
import ContentElement from '@/components/content-block-form/ContentElement.vue';
|
||||||
import {
|
import {
|
||||||
insertAtIndex,
|
insertAtIndex,
|
||||||
moveToIndex,
|
moveToIndex,
|
||||||
removeAtIndex,
|
removeAtIndex,
|
||||||
replaceAtIndex,
|
replaceAtIndex,
|
||||||
swapElements
|
swapElements,
|
||||||
} from '@/graphql/immutable-operations';
|
} from '@/graphql/immutable-operations';
|
||||||
|
|
||||||
import {CHOOSER, transformInnerContents} from '@/components/content-block-form/helpers.js';
|
import { CHOOSER, transformInnerContents } from '@/components/content-block-form/helpers.js';
|
||||||
import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue';
|
import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue';
|
||||||
import {ContentBlock, numberOrUndefined} from "@/@types";
|
import { ContentBlock, numberOrUndefined } from '@/@types';
|
||||||
import {DEFAULT_FEATURE_SET} from "@/consts/features.consts";
|
import { DEFAULT_FEATURE_SET } from '@/consts/features.consts';
|
||||||
|
|
||||||
// TODO: refactor this file, it's huuuuuge!
|
// TODO: refactor this file, it's huuuuuge!
|
||||||
interface ContentBlockFormData {
|
interface ContentBlockFormData {
|
||||||
localContentBlock: any;
|
localContentBlock: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
|
||||||
contentBlock: {
|
|
||||||
type: Object as PropType<ContentBlock>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
features: {
|
|
||||||
type: String,
|
|
||||||
default: DEFAULT_FEATURE_SET
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
provide(): object {
|
contentBlock: {
|
||||||
return {
|
type: Object as PropType<ContentBlock>,
|
||||||
features: this.features
|
required: true,
|
||||||
};
|
|
||||||
},
|
},
|
||||||
components: {
|
features: {
|
||||||
ContentElementActions,
|
type: String,
|
||||||
ContentElement,
|
default: DEFAULT_FEATURE_SET,
|
||||||
AddContentLink,
|
|
||||||
InputWithLabel,
|
|
||||||
ContentFormSection,
|
|
||||||
Toggle,
|
|
||||||
},
|
},
|
||||||
data(): ContentBlockFormData {
|
},
|
||||||
return {
|
provide(): object {
|
||||||
localContentBlock: Object.assign({}, {
|
return {
|
||||||
|
features: this.features,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ContentElementActions,
|
||||||
|
ContentElement,
|
||||||
|
AddContentLink,
|
||||||
|
InputWithLabel,
|
||||||
|
ContentFormSection,
|
||||||
|
Toggle,
|
||||||
|
},
|
||||||
|
data(): ContentBlockFormData {
|
||||||
|
return {
|
||||||
|
localContentBlock: Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
title: this.contentBlock.title,
|
title: this.contentBlock.title,
|
||||||
// contents: [...this.contentBlock.contents],
|
// contents: [...this.contentBlock.contents],
|
||||||
contents: transformInnerContents([...this.contentBlock.contents]),
|
contents: transformInnerContents([...this.contentBlock.contents]),
|
||||||
id: this.contentBlock.id || undefined,
|
id: this.contentBlock.id || undefined,
|
||||||
isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task',
|
isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task',
|
||||||
}),
|
}
|
||||||
};
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isValid(): boolean {
|
||||||
|
return this.localContentBlock.title > '';
|
||||||
},
|
},
|
||||||
computed: {
|
hasDefaultFeatures(): boolean {
|
||||||
isValid(): boolean {
|
return this.features === DEFAULT_FEATURE_SET;
|
||||||
return this.localContentBlock.title > '';
|
},
|
||||||
},
|
},
|
||||||
hasDefaultFeatures(): boolean {
|
methods: {
|
||||||
return this.features === DEFAULT_FEATURE_SET;
|
update(index: number, element: any, parent?: number) {
|
||||||
|
if (parent === undefined) {
|
||||||
|
// element is top level
|
||||||
|
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, index, element);
|
||||||
|
} else {
|
||||||
|
const parentBlock = this.localContentBlock.contents[parent];
|
||||||
|
|
||||||
|
const newElementContents = replaceAtIndex(parentBlock.contents, index, element);
|
||||||
|
const newBlock = {
|
||||||
|
...parentBlock,
|
||||||
|
contents: newElementContents,
|
||||||
|
};
|
||||||
|
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, parent, newBlock);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
addBlock(afterOuterIndex: number, innerIndex?: number) {
|
||||||
update(index: number, element: any, parent?: number) {
|
if (innerIndex !== undefined) {
|
||||||
if (parent === undefined) {
|
const block = this.localContentBlock.contents[afterOuterIndex];
|
||||||
// element is top level
|
const element = {
|
||||||
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, index, element);
|
...block,
|
||||||
} else {
|
contents: insertAtIndex(block.contents, innerIndex + 1, {
|
||||||
const parentBlock = this.localContentBlock.contents[parent];
|
|
||||||
|
|
||||||
const newElementContents = replaceAtIndex(parentBlock.contents, index, element);
|
|
||||||
const newBlock = {
|
|
||||||
...parentBlock,
|
|
||||||
contents: newElementContents,
|
|
||||||
};
|
|
||||||
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, parent, newBlock);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addBlock(afterOuterIndex: number, innerIndex?: number) {
|
|
||||||
if (innerIndex !== undefined) {
|
|
||||||
const block = this.localContentBlock.contents[afterOuterIndex];
|
|
||||||
const element = {
|
|
||||||
...block,
|
|
||||||
contents: insertAtIndex(block.contents, innerIndex + 1, {
|
|
||||||
id: -1,
|
|
||||||
type: CHOOSER,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, afterOuterIndex, element);
|
|
||||||
} else {
|
|
||||||
const element = {
|
|
||||||
id: -1,
|
id: -1,
|
||||||
type: CHOOSER,
|
type: CHOOSER,
|
||||||
includeListOption: true,
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.localContentBlock.contents = insertAtIndex(this.localContentBlock.contents, afterOuterIndex + 1, element);
|
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, afterOuterIndex, element);
|
||||||
}
|
} else {
|
||||||
},
|
const element = {
|
||||||
remove(outer: number, inner?: number, askForConfirmation = true) {
|
id: -1,
|
||||||
if (askForConfirmation) {
|
type: CHOOSER,
|
||||||
this.$modal.open('confirm')
|
includeListOption: true,
|
||||||
.then(() => {
|
};
|
||||||
this.executeRemoval(outer, inner);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
|
|
||||||
});
|
this.localContentBlock.contents = insertAtIndex(this.localContentBlock.contents, afterOuterIndex + 1, element);
|
||||||
} else {
|
}
|
||||||
this.executeRemoval(outer, inner);
|
},
|
||||||
}
|
remove(outer: number, inner?: number, askForConfirmation = true) {
|
||||||
},
|
if (askForConfirmation) {
|
||||||
shift(outer: number, inner: numberOrUndefined = undefined, distance: number) {
|
this.$modal
|
||||||
if (inner === undefined) {
|
.open('confirm')
|
||||||
this.localContentBlock.contents = swapElements(this.localContentBlock.contents, outer, outer + distance);
|
.then(() => {
|
||||||
} else {
|
this.executeRemoval(outer, inner);
|
||||||
const {contents} = this.localContentBlock;
|
})
|
||||||
const outerElement = contents[outer];
|
.catch(() => {});
|
||||||
const newOuterElement = {
|
} else {
|
||||||
...outerElement,
|
this.executeRemoval(outer, inner);
|
||||||
contents: swapElements(outerElement.contents, inner, inner + distance),
|
}
|
||||||
};
|
},
|
||||||
this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
|
shift(outer: number, inner: numberOrUndefined = undefined, distance: number) {
|
||||||
}
|
if (inner === undefined) {
|
||||||
},
|
this.localContentBlock.contents = swapElements(this.localContentBlock.contents, outer, outer + distance);
|
||||||
top(outer: number, inner: numberOrUndefined = undefined) {
|
} else {
|
||||||
if (inner === undefined) {
|
const { contents } = this.localContentBlock;
|
||||||
this.localContentBlock.contents = moveToIndex(this.localContentBlock.contents, outer, 0);
|
const outerElement = contents[outer];
|
||||||
} else {
|
const newOuterElement = {
|
||||||
const {contents} = this.localContentBlock;
|
...outerElement,
|
||||||
const outerElement = contents[outer];
|
contents: swapElements(outerElement.contents, inner, inner + distance),
|
||||||
const newOuterElement = {
|
};
|
||||||
...outerElement,
|
this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
|
||||||
contents: moveToIndex(outerElement.contents, inner, 0),
|
}
|
||||||
};
|
},
|
||||||
this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
|
top(outer: number, inner: numberOrUndefined = undefined) {
|
||||||
}
|
if (inner === undefined) {
|
||||||
},
|
this.localContentBlock.contents = moveToIndex(this.localContentBlock.contents, outer, 0);
|
||||||
up(outer: number, inner: numberOrUndefined = undefined) {
|
} else {
|
||||||
this.shift(outer, inner, -1);
|
const { contents } = this.localContentBlock;
|
||||||
},
|
const outerElement = contents[outer];
|
||||||
down(outer: number, inner: numberOrUndefined = undefined) {
|
const newOuterElement = {
|
||||||
this.shift(outer, inner, 1);
|
...outerElement,
|
||||||
},
|
contents: moveToIndex(outerElement.contents, inner, 0),
|
||||||
bottom(outer: number, inner: numberOrUndefined = undefined) {
|
};
|
||||||
if (inner === undefined) {
|
this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
|
||||||
const maxIndex = this.localContentBlock.contents.length - 1;
|
}
|
||||||
this.localContentBlock.contents = moveToIndex(this.localContentBlock.contents, outer, maxIndex);
|
},
|
||||||
} else {
|
up(outer: number, inner: numberOrUndefined = undefined) {
|
||||||
const {contents} = this.localContentBlock;
|
this.shift(outer, inner, -1);
|
||||||
const outerElement = contents[outer];
|
},
|
||||||
const maxIndex = outerElement.contents.length - 1;
|
down(outer: number, inner: numberOrUndefined = undefined) {
|
||||||
const newOuterElement = {
|
this.shift(outer, inner, 1);
|
||||||
...outerElement,
|
},
|
||||||
contents: moveToIndex(outerElement.contents, inner, maxIndex),
|
bottom(outer: number, inner: numberOrUndefined = undefined) {
|
||||||
};
|
if (inner === undefined) {
|
||||||
this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
|
const maxIndex = this.localContentBlock.contents.length - 1;
|
||||||
}
|
this.localContentBlock.contents = moveToIndex(this.localContentBlock.contents, outer, maxIndex);
|
||||||
},
|
} else {
|
||||||
executeRemoval(outer: number, inner: numberOrUndefined = undefined) {
|
const { contents } = this.localContentBlock;
|
||||||
if (inner === undefined) {
|
const outerElement = contents[outer];
|
||||||
// not a list item container, just remove the element from the outer array
|
const maxIndex = outerElement.contents.length - 1;
|
||||||
this.localContentBlock.contents = removeAtIndex(this.localContentBlock.contents, outer);
|
const newOuterElement = {
|
||||||
} else {
|
...outerElement,
|
||||||
let prevInnerContents = this.localContentBlock.contents[outer].contents;
|
contents: moveToIndex(outerElement.contents, inner, maxIndex),
|
||||||
let innerContents = removeAtIndex(prevInnerContents, inner);
|
};
|
||||||
|
this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
executeRemoval(outer: number, inner: numberOrUndefined = undefined) {
|
||||||
|
if (inner === undefined) {
|
||||||
|
// not a list item container, just remove the element from the outer array
|
||||||
|
this.localContentBlock.contents = removeAtIndex(this.localContentBlock.contents, outer);
|
||||||
|
} else {
|
||||||
|
let prevInnerContents = this.localContentBlock.contents[outer].contents;
|
||||||
|
let innerContents = removeAtIndex(prevInnerContents, inner);
|
||||||
|
|
||||||
if (innerContents.length) {
|
if (innerContents.length) {
|
||||||
/*
|
/*
|
||||||
there is still an element inside the outer element after removal,
|
there is still an element inside the outer element after removal,
|
||||||
so we replace the previous element in the outer array with the new one with fewer contents
|
so we replace the previous element in the outer array with the new one with fewer contents
|
||||||
*/
|
*/
|
||||||
let element = {
|
let element = {
|
||||||
...this.localContentBlock.contents[outer],
|
...this.localContentBlock.contents[outer],
|
||||||
contents: innerContents,
|
contents: innerContents,
|
||||||
};
|
};
|
||||||
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, outer, element);
|
this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, outer, element);
|
||||||
} else {
|
} else {
|
||||||
// inner contents is now empty, remove the whole element from the outer array
|
// inner contents is now empty, remove the whole element from the outer array
|
||||||
this.localContentBlock.contents = removeAtIndex(this.localContentBlock.contents, outer);
|
this.localContentBlock.contents = removeAtIndex(this.localContentBlock.contents, outer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
save(contentBlock: ContentBlock) {
|
|
||||||
this.$emit('save', contentBlock);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
save(contentBlock: ContentBlock) {
|
||||||
});
|
this.$emit('save', contentBlock);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
// override parent page properties
|
// override parent page properties
|
||||||
.layout--no-scroll {
|
.layout--no-scroll {
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
.module-page {
|
.module-page {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
grid-template-rows: 60px 1fr;
|
grid-template-rows: 60px 1fr;
|
||||||
padding-bottom: $small-spacing;
|
padding-bottom: $small-spacing;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-block-form {
|
.content-block-form {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 100vw;
|
grid-template-columns: 100vw;
|
||||||
grid-template-rows: 85vh 80px;
|
grid-template-rows: 85vh 80px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'content'
|
'content'
|
||||||
'footer';
|
'footer';
|
||||||
|
|
||||||
@media (-webkit-min-device-pixel-ratio: 1.25) {
|
@media (-webkit-min-device-pixel-ratio: 1.25) {
|
||||||
grid-template-rows: 80vh auto;
|
grid-template-rows: 80vh auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
@include heading-1;
|
||||||
|
}
|
||||||
|
|
||||||
&__heading {
|
&__task-toggle {
|
||||||
@include heading-1;
|
margin-bottom: $large-spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__task-toggle {
|
&__add-button {
|
||||||
margin-bottom: $large-spacing;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&__add-button {
|
&__segment {
|
||||||
}
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
&__segment {
|
margin-bottom: $large-spacing;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
|
|
||||||
margin-bottom: $large-spacing;
|
:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__actions {
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
grid-area: content;
|
|
||||||
overflow-x: visible;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 10px;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& > * { // we make an exception and use a wildcard here
|
|
||||||
width: 800px;
|
|
||||||
max-width: 100vw;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
padding: $medium-spacing 0;
|
|
||||||
border-top: 1px solid $color-silver;
|
|
||||||
margin-top: auto;
|
|
||||||
grid-area: footer;
|
|
||||||
justify-content: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
width: 800px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
grid-area: content;
|
||||||
|
overflow-x: visible;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 10px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
// we make an exception and use a wildcard here
|
||||||
|
width: 800px;
|
||||||
|
max-width: 100vw;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
padding: $medium-spacing 0;
|
||||||
|
border-top: 1px solid $color-silver;
|
||||||
|
margin-top: auto;
|
||||||
|
grid-area: footer;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttons {
|
||||||
|
width: 800px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
@remove="$emit('remove', false)"
|
@remove="$emit('remove', false)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<!-- Content Forms -->
|
<!-- Content Forms -->
|
||||||
<content-form-section
|
<content-form-section
|
||||||
:title="title"
|
:title="title"
|
||||||
|
|
@ -27,14 +26,10 @@
|
||||||
:class="['content-element__component']"
|
:class="['content-element__component']"
|
||||||
v-bind="element"
|
v-bind="element"
|
||||||
:is="component"
|
:is="component"
|
||||||
|
|
||||||
@change-text="changeText"
|
@change-text="changeText"
|
||||||
|
|
||||||
@link-change-url="changeUrl"
|
@link-change-url="changeUrl"
|
||||||
@change-url="changeUrl"
|
@change-url="changeUrl"
|
||||||
|
|
||||||
@switch-to-document="switchToDocument"
|
@switch-to-document="switchToDocument"
|
||||||
|
|
||||||
@assignment-change-title="changeAssignmentTitle"
|
@assignment-change-title="changeAssignmentTitle"
|
||||||
@assignment-change-assignment="changeAssignmentAssignment"
|
@assignment-change-assignment="changeAssignmentAssignment"
|
||||||
/>
|
/>
|
||||||
|
|
@ -44,312 +39,321 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentFormSection from '@/components/content-block-form/ContentFormSection';
|
import ContentFormSection from '@/components/content-block-form/ContentFormSection';
|
||||||
import ContentElementActions from '@/components/content-block-form/ContentElementActions';
|
import ContentElementActions from '@/components/content-block-form/ContentElementActions';
|
||||||
|
|
||||||
const TrashIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon');
|
const TrashIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/TrashIcon');
|
||||||
const ContentBlockElementChooserWidget = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/ContentBlockElementChooserWidget');
|
const ContentBlockElementChooserWidget = () =>
|
||||||
const LinkForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/LinkForm');
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/ContentBlockElementChooserWidget');
|
||||||
const VideoForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/VideoForm');
|
const LinkForm = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/LinkForm');
|
||||||
const ImageForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/ImageForm');
|
const VideoForm = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/VideoForm');
|
||||||
const DocumentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/DocumentForm');
|
const ImageForm = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/ImageForm');
|
||||||
const AssignmentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/AssignmentForm');
|
const DocumentForm = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/DocumentForm');
|
||||||
const TextForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/TipTap.vue');
|
const AssignmentForm = () =>
|
||||||
const SubtitleForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/SubtitleForm');
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/AssignmentForm');
|
||||||
// readonly blocks
|
const TextForm = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/TipTap.vue');
|
||||||
const Assignment = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/assignment/Assignment');
|
const SubtitleForm = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-forms/SubtitleForm');
|
||||||
const SurveyBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/SurveyBlock');
|
// readonly blocks
|
||||||
const Solution = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/Solution');
|
const Assignment = () =>
|
||||||
const ImageBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ImageBlock');
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/assignment/Assignment');
|
||||||
const Instruction = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/Instruction');
|
const SurveyBlock = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/SurveyBlock');
|
||||||
const ModuleRoomSlug = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ModuleRoomSlug');
|
const Solution = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/Solution');
|
||||||
const CmsDocumentBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/CmsDocumentBlock');
|
const ImageBlock = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/ImageBlock');
|
||||||
const ThinglinkBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ThinglinkBlock');
|
const Instruction = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/Instruction');
|
||||||
const InfogramBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/InfogramBlock');
|
const ModuleRoomSlug = () =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/ModuleRoomSlug');
|
||||||
|
const CmsDocumentBlock = () =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/CmsDocumentBlock');
|
||||||
|
const ThinglinkBlock = () =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/ThinglinkBlock');
|
||||||
|
const InfogramBlock = () => import(/* webpackChunkName: "content-forms" */ '@/components/content-blocks/InfogramBlock');
|
||||||
|
|
||||||
const CHOOSER = 'content-block-element-chooser-widget';
|
const CHOOSER = 'content-block-element-chooser-widget';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
element: {
|
element: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
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,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
// is this element at the top level, or is it nested? we assume top level
|
||||||
components: {
|
topLevel: {
|
||||||
ContentElementActions,
|
type: Boolean,
|
||||||
ContentFormSection,
|
default: true,
|
||||||
TrashIcon,
|
|
||||||
ContentBlockElementChooserWidget,
|
|
||||||
LinkForm,
|
|
||||||
VideoForm,
|
|
||||||
ImageForm,
|
|
||||||
DocumentForm,
|
|
||||||
AssignmentForm,
|
|
||||||
TextForm,
|
|
||||||
SubtitleForm,
|
|
||||||
SurveyBlock,
|
|
||||||
Solution,
|
|
||||||
ImageBlock,
|
|
||||||
Instruction,
|
|
||||||
ModuleRoomSlug,
|
|
||||||
CmsDocumentBlock,
|
|
||||||
InfogramBlock,
|
|
||||||
ThinglinkBlock,
|
|
||||||
Assignment
|
|
||||||
},
|
},
|
||||||
|
firstElement: {
|
||||||
computed: {
|
type: Boolean,
|
||||||
actions() {
|
required: true,
|
||||||
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;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
lastElement: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
components: {
|
||||||
getType(element) {
|
ContentElementActions,
|
||||||
switch (element.type) {
|
ContentFormSection,
|
||||||
case 'subtitle':
|
TrashIcon,
|
||||||
return {
|
ContentBlockElementChooserWidget,
|
||||||
component: 'subtitle-form',
|
LinkForm,
|
||||||
title: 'Untertitel',
|
VideoForm,
|
||||||
icon: 'title-icon',
|
ImageForm,
|
||||||
};
|
DocumentForm,
|
||||||
case 'link_block':
|
AssignmentForm,
|
||||||
return {
|
TextForm,
|
||||||
component: 'link-form',
|
SubtitleForm,
|
||||||
title: 'Link',
|
SurveyBlock,
|
||||||
icon: 'link-icon',
|
Solution,
|
||||||
};
|
ImageBlock,
|
||||||
case 'video_block':
|
Instruction,
|
||||||
return {
|
ModuleRoomSlug,
|
||||||
component: 'video-form',
|
CmsDocumentBlock,
|
||||||
title: 'Video',
|
InfogramBlock,
|
||||||
icon: 'video-icon',
|
ThinglinkBlock,
|
||||||
};
|
Assignment,
|
||||||
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) {
|
computed: {
|
||||||
el = {
|
actions() {
|
||||||
type: 'content_list_item',
|
return {
|
||||||
contents: [el],
|
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',
|
||||||
};
|
};
|
||||||
}
|
case 'link_block':
|
||||||
this.update(el);
|
return {
|
||||||
},
|
component: 'link-form',
|
||||||
update(element) {
|
title: 'Link',
|
||||||
this.$emit('update', element);
|
icon: 'link-icon',
|
||||||
},
|
};
|
||||||
switchToDocument(value) {
|
case 'video_block':
|
||||||
this.changeType('document_block', value);
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-element {
|
.content-element {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
&__actions {
|
&__actions {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
align-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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content-element-actions">
|
<div class="content-element-actions">
|
||||||
<button
|
<button class="icon-button" @click.stop="toggle(true)">
|
||||||
class="icon-button"
|
|
||||||
@click.stop="toggle(true)"
|
|
||||||
>
|
|
||||||
<ellipses class="icon-button__icon" />
|
<ellipses class="icon-button__icon" />
|
||||||
</button>
|
</button>
|
||||||
<widget-popover
|
<widget-popover class="content-element-actions__popover" :no-padding="true" v-if="show" @hide-me="toggle(false)">
|
||||||
class="content-element-actions__popover"
|
|
||||||
:no-padding="true"
|
|
||||||
v-if="show"
|
|
||||||
@hide-me="toggle(false)"
|
|
||||||
>
|
|
||||||
<section class="content-element-actions__section">
|
<section class="content-element-actions__section">
|
||||||
<button-with-icon-and-text
|
<button-with-icon-and-text
|
||||||
class="content-element-actions__button"
|
class="content-element-actions__button"
|
||||||
|
|
@ -63,84 +55,82 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import WidgetPopover from '@/components/ui/WidgetPopover.vue';
|
import WidgetPopover from '@/components/ui/WidgetPopover.vue';
|
||||||
import Ellipses from '@/components/icons/Ellipses.vue';
|
import Ellipses from '@/components/icons/Ellipses.vue';
|
||||||
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText.vue';
|
import ButtonWithIconAndText from '@/components/ui/ButtonWithIconAndText.vue';
|
||||||
import {ActionOptions} from "@/@types";
|
import { ActionOptions } from '@/@types';
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
actions: {
|
actions: {
|
||||||
type: Object as () => ActionOptions
|
type: Object as () => ActionOptions,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
components: {ButtonWithIconAndText, Ellipses, WidgetPopover},
|
},
|
||||||
|
components: { ButtonWithIconAndText, Ellipses, WidgetPopover },
|
||||||
|
|
||||||
data: (): Data => ({
|
data: (): Data => ({
|
||||||
show: false,
|
show: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggle(show: boolean) {
|
toggle(show: boolean) {
|
||||||
this.show = show;
|
this.show = show;
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.show = false;
|
|
||||||
},
|
|
||||||
up() {
|
|
||||||
this.$emit('move-up');
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
down() {
|
|
||||||
this.$emit('move-down');
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
top() {
|
|
||||||
this.$emit('move-top');
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
bottom() {
|
|
||||||
this.$emit('move-bottom');
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
emitAndClose(event: string) {
|
|
||||||
this.$emit(event);
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
close() {
|
||||||
|
this.show = false;
|
||||||
|
},
|
||||||
|
up() {
|
||||||
|
this.$emit('move-up');
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
down() {
|
||||||
|
this.$emit('move-down');
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
top() {
|
||||||
|
this.$emit('move-top');
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
bottom() {
|
||||||
|
this.$emit('move-bottom');
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
emitAndClose(event: string) {
|
||||||
|
this.$emit(event);
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-element-actions {
|
.content-element-actions {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&__popover {
|
&__popover {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
transform: translateY($small-spacing);
|
transform: translateY($small-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
&__section {
|
||||||
|
border-bottom: 1px solid $color-silver-dark;
|
||||||
|
padding: $medium-spacing $small-spacing;
|
||||||
|
|
||||||
&__section {
|
&:last-child {
|
||||||
border-bottom: 1px solid $color-silver-dark;
|
border-bottom: 0;
|
||||||
padding: $medium-spacing $small-spacing;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__button {
|
|
||||||
margin-bottom: $medium-spacing;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
margin-bottom: $medium-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content-form-section">
|
<div class="content-form-section">
|
||||||
<h2 class="content-form-section__heading">
|
<h2 class="content-form-section__heading">
|
||||||
<component
|
<component class="content-form-section__icon" :is="icon" />
|
||||||
class="content-form-section__icon"
|
<span class="content-form-section__title" data-cy="content-form-section-title">{{ title }}</span>
|
||||||
:is="icon"
|
|
||||||
/> <span
|
|
||||||
class="content-form-section__title"
|
|
||||||
data-cy="content-form-section-title"
|
|
||||||
>{{ title }}</span>
|
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<content-element-actions
|
<content-element-actions
|
||||||
|
|
@ -27,74 +22,73 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import formElementIcons from '@/components/ui/form-element-icons.js';
|
import formElementIcons from '@/components/ui/form-element-icons.js';
|
||||||
import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue';
|
import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue';
|
||||||
import {ActionOptions} from "@/@types";
|
import { ActionOptions } from '@/@types';
|
||||||
|
|
||||||
|
export default {
|
||||||
export default {
|
props: {
|
||||||
props: {
|
title: {
|
||||||
title: {
|
type: String,
|
||||||
type: String,
|
default: '',
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
type: Object as () => ActionOptions,
|
|
||||||
default: () => {}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
components: {
|
icon: {
|
||||||
ContentElementActions,
|
type: String,
|
||||||
...formElementIcons
|
default: '',
|
||||||
}
|
},
|
||||||
};
|
actions: {
|
||||||
|
type: Object as () => ActionOptions,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ContentElementActions,
|
||||||
|
...formElementIcons,
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-form-section {
|
.content-form-section {
|
||||||
@include default-box-shadow;
|
@include default-box-shadow;
|
||||||
border-radius: $default-border-radius;
|
border-radius: $default-border-radius;
|
||||||
padding: $small-spacing $medium-spacing;
|
padding: $small-spacing $medium-spacing;
|
||||||
margin-bottom: $medium-spacing;
|
margin-bottom: $medium-spacing;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-template-rows: auto;
|
grid-template-rows: auto;
|
||||||
grid-template-areas: 'h a' 'c c';
|
grid-template-areas: 'h a' 'c c';
|
||||||
|
align-items: center;
|
||||||
|
grid-row-gap: $medium-spacing;
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-row-gap: $medium-spacing;
|
grid-area: h;
|
||||||
|
margin-bottom: 0;
|
||||||
&__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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -18,166 +18,150 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<add-content-element
|
<add-content-element :index="-1" class="contents-form__add" @add-element="addElement" />
|
||||||
:index="-1"
|
<div class="contents-form__element" v-for="(element, index) in localContentBlock.contents" :key="index">
|
||||||
class="contents-form__add"
|
<content-element :element="element" @update="update(index, $event)" @remove="remove(index)" />
|
||||||
@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
|
<add-content-element :index="index" class="contents-form__add" @add-element="addElement" />
|
||||||
:index="index"
|
|
||||||
class="contents-form__add"
|
|
||||||
@add-element="addElement"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
:class="{'button--disabled': disableSave}"
|
:class="{ 'button--disabled': disableSave }"
|
||||||
class="button button--primary"
|
class="button button--primary"
|
||||||
data-cy="modal-save-button"
|
data-cy="modal-save-button"
|
||||||
@click="save"
|
@click="save"
|
||||||
>Speichern</a>
|
>Speichern</a
|
||||||
<a
|
>
|
||||||
class="button"
|
<a class="button" @click="$emit('hide')">Abbrechen</a>
|
||||||
@click="$emit('hide')"
|
|
||||||
>Abbrechen</a>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {meQuery} from '@/graphql/queries';
|
import { meQuery } from '@/graphql/queries';
|
||||||
|
|
||||||
const ModalInput = () => import(/* webpackChunkName: "content-forms" */'@/components/ModalInput');
|
const ModalInput = () => import(/* webpackChunkName: "content-forms" */ '@/components/ModalInput');
|
||||||
const AddContentElement = () => import(/* webpackChunkName: "content-forms" */'@/components/AddContentElement');
|
const AddContentElement = () => import(/* webpackChunkName: "content-forms" */ '@/components/AddContentElement');
|
||||||
const ContentElement = () => import(/* webpackChunkName: "content-forms" */'@/components/content-block-form/ContentElement');
|
const ContentElement = () =>
|
||||||
|
import(/* webpackChunkName: "content-forms" */ '@/components/content-block-form/ContentElement');
|
||||||
|
|
||||||
const Modal = () => import('@/components/Modal.vue');
|
const Modal = () => import('@/components/Modal.vue');
|
||||||
const Checkbox = () => import('@/components/ui/Checkbox.vue');
|
const Checkbox = () => import('@/components/ui/Checkbox.vue');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
contentBlock: Object,
|
contentBlock: Object,
|
||||||
blockType: {
|
blockType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'ContentBlock',
|
default: 'ContentBlock',
|
||||||
},
|
|
||||||
showTaskSelection: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
disableSave: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
showTaskSelection: {
|
||||||
components: {
|
type: Boolean,
|
||||||
ContentElement,
|
default: false,
|
||||||
Modal,
|
|
||||||
ModalInput,
|
|
||||||
AddContentElement,
|
|
||||||
Checkbox,
|
|
||||||
},
|
},
|
||||||
|
disableSave: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
components: {
|
||||||
return {
|
ContentElement,
|
||||||
error: false,
|
Modal,
|
||||||
localContentBlock: Object.assign({}, {
|
ModalInput,
|
||||||
|
AddContentElement,
|
||||||
|
Checkbox,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
error: false,
|
||||||
|
localContentBlock: Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
title: this.contentBlock.title,
|
title: this.contentBlock.title,
|
||||||
contents: [...this.contentBlock.contents],
|
contents: [...this.contentBlock.contents],
|
||||||
id: this.contentBlock.id || undefined,
|
id: this.contentBlock.id || undefined,
|
||||||
isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task',
|
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) {
|
me: {},
|
||||||
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);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.contents-form {
|
.contents-form {
|
||||||
/* top level does not exist, because of the modal */
|
/* top level does not exist, because of the modal */
|
||||||
|
|
||||||
&__element {
|
&__element {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
&__element-component {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__remove {
|
|
||||||
}
|
|
||||||
|
|
||||||
&__trash-icon {
|
|
||||||
}
|
|
||||||
|
|
||||||
&__add {
|
|
||||||
grid-column: 1 / span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__task {
|
|
||||||
margin: 15px 0 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__element-component {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__remove {
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trash-icon {
|
||||||
|
}
|
||||||
|
|
||||||
|
&__add {
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__task {
|
||||||
|
margin: 15px 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,77 +1,75 @@
|
||||||
<template>
|
<template>
|
||||||
<contents-form
|
<contents-form :content-block="contentBlock" :show-task-selection="true" @save="saveContentBlock" @hide="hideModal" />
|
||||||
:content-block="contentBlock"
|
|
||||||
:show-task-selection="true"
|
|
||||||
@save="saveContentBlock"
|
|
||||||
@hide="hideModal"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentsForm from '@/components/content-block-form/ContentsForm';
|
import ContentsForm from '@/components/content-block-form/ContentsForm';
|
||||||
|
|
||||||
import store from '@/store/index';
|
import store from '@/store/index';
|
||||||
|
|
||||||
import EDIT_CONTENT_BLOCK_MUTATION from 'gql/mutations/editContentBlock.gql';
|
import EDIT_CONTENT_BLOCK_MUTATION from 'gql/mutations/editContentBlock.gql';
|
||||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||||
import CONTENT_BLOCK_QUERY from '@/graphql/gql/queries/contentBlockQuery.gql';
|
import CONTENT_BLOCK_QUERY from '@/graphql/gql/queries/contentBlockQuery.gql';
|
||||||
import { setUserBlockType } from '@/helpers/content-block';
|
import { setUserBlockType } from '@/helpers/content-block';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ContentsForm
|
ContentsForm,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
contentBlock: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
// debugger;
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
hideModal() {
|
||||||
|
this.$store.dispatch('resetCurrentNoteBlock');
|
||||||
|
this.$store.dispatch('hideModal');
|
||||||
},
|
},
|
||||||
|
saveContentBlock(contentBlock) {
|
||||||
data() {
|
this.$apollo
|
||||||
return {
|
.mutate({
|
||||||
contentBlock: {}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
// debugger;
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
hideModal() {
|
|
||||||
this.$store.dispatch('resetCurrentNoteBlock');
|
|
||||||
this.$store.dispatch('hideModal');
|
|
||||||
},
|
|
||||||
saveContentBlock(contentBlock) {
|
|
||||||
this.$apollo.mutate({
|
|
||||||
mutation: EDIT_CONTENT_BLOCK_MUTATION,
|
mutation: EDIT_CONTENT_BLOCK_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
contentBlock: {
|
contentBlock: {
|
||||||
title: contentBlock.title,
|
title: contentBlock.title,
|
||||||
contents: contentBlock.contents.filter(value => Object.keys(value).length > 0),
|
contents: contentBlock.contents.filter((value) => Object.keys(value).length > 0),
|
||||||
type: setUserBlockType(contentBlock.isAssignment)
|
type: setUserBlockType(contentBlock.isAssignment),
|
||||||
},
|
},
|
||||||
id: contentBlock.id
|
id: contentBlock.id,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
refetchQueries: [{
|
refetchQueries: [
|
||||||
query: MODULE_DETAILS_QUERY,
|
{
|
||||||
variables: {
|
query: MODULE_DETAILS_QUERY,
|
||||||
slug: this.$route.params.slug
|
variables: {
|
||||||
}
|
slug: this.$route.params.slug,
|
||||||
}]
|
},
|
||||||
}).then(() => {
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
this.hideModal();
|
this.hideModal();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
contentBlock() {
|
contentBlock() {
|
||||||
return {
|
return {
|
||||||
query: CONTENT_BLOCK_QUERY,
|
query: CONTENT_BLOCK_QUERY,
|
||||||
variables: {
|
variables: {
|
||||||
id: store.state.currentNoteBlock
|
id: store.state.currentNoteBlock,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -9,60 +9,62 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentsForm from '@/components/content-block-form/ContentsForm';
|
import ContentsForm from '@/components/content-block-form/ContentsForm';
|
||||||
|
|
||||||
import NEW_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/addContentBlock.gql';
|
import NEW_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/addContentBlock.gql';
|
||||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||||
import {setUserBlockType} from '@/helpers/content-block';
|
import { setUserBlockType } from '@/helpers/content-block';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ContentsForm
|
ContentsForm,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
contentBlock: {
|
contentBlock: {
|
||||||
title: '',
|
title: '',
|
||||||
contents: [
|
contents: [{}],
|
||||||
{}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
saving: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
hideModal() {
|
|
||||||
this.$store.dispatch('resetContentBlockPosition');
|
|
||||||
this.$store.dispatch('hideModal');
|
|
||||||
},
|
},
|
||||||
saveContentBlock(contentBlock) {
|
saving: false,
|
||||||
this.saving = true;
|
};
|
||||||
this.$apollo.mutate({
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
hideModal() {
|
||||||
|
this.$store.dispatch('resetContentBlockPosition');
|
||||||
|
this.$store.dispatch('hideModal');
|
||||||
|
},
|
||||||
|
saveContentBlock(contentBlock) {
|
||||||
|
this.saving = true;
|
||||||
|
this.$apollo
|
||||||
|
.mutate({
|
||||||
mutation: NEW_CONTENT_BLOCK_MUTATION,
|
mutation: NEW_CONTENT_BLOCK_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
contentBlock: {
|
contentBlock: {
|
||||||
title: contentBlock.title,
|
title: contentBlock.title,
|
||||||
contents: contentBlock.contents.filter(value => Object.keys(value).length > 0),
|
contents: contentBlock.contents.filter((value) => Object.keys(value).length > 0),
|
||||||
type: setUserBlockType(contentBlock.isAssignment)
|
type: setUserBlockType(contentBlock.isAssignment),
|
||||||
},
|
},
|
||||||
after: this.$store.state.contentBlockPosition.after,
|
after: this.$store.state.contentBlockPosition.after,
|
||||||
parent: this.$store.state.contentBlockPosition.parent
|
parent: this.$store.state.contentBlockPosition.parent,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
refetchQueries: [{
|
refetchQueries: [
|
||||||
query: MODULE_DETAILS_QUERY,
|
{
|
||||||
variables: {
|
query: MODULE_DETAILS_QUERY,
|
||||||
slug: this.$route.params.slug
|
variables: {
|
||||||
}
|
slug: this.$route.params.slug,
|
||||||
}]
|
},
|
||||||
}).then(() => {
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
this.hideModal();
|
this.hideModal();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,46 @@
|
||||||
export const CHOOSER = 'content-block-element-chooser-widget';
|
export const CHOOSER = 'content-block-element-chooser-widget';
|
||||||
export const chooserFilter = value => value.type !== CHOOSER;
|
export const chooserFilter = (value) => value.type !== CHOOSER;
|
||||||
export const USER_CONTENT_TYPES = ['subtitle', 'link_block', 'video_block', 'image_url_block', 'text_block', 'assignment', 'document_block'];
|
export const USER_CONTENT_TYPES = [
|
||||||
|
'subtitle',
|
||||||
|
'link_block',
|
||||||
|
'video_block',
|
||||||
|
'image_url_block',
|
||||||
|
'text_block',
|
||||||
|
'assignment',
|
||||||
|
'document_block',
|
||||||
|
];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Users can only edit certain types of contents, the rest can only be re-ordered. We only care about their id, we won't
|
Users can only edit certain types of contents, the rest can only be re-ordered. We only care about their id, we won't
|
||||||
send anything else to the server about them
|
send anything else to the server about them
|
||||||
*/
|
*/
|
||||||
export const simplifyContents = (contents) => {
|
export const simplifyContents = (contents) => {
|
||||||
return contents.map(c => {
|
return contents.map((c) => {
|
||||||
if (USER_CONTENT_TYPES.includes(c.type)) {
|
if (USER_CONTENT_TYPES.includes(c.type)) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
if (c.type === 'content_list_item') {
|
if (c.type === 'content_list_item') {
|
||||||
return {
|
return {
|
||||||
...c,
|
...c,
|
||||||
contents: simplifyContents(c.contents)
|
contents: simplifyContents(c.contents),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
id: c.id,
|
id: c.id,
|
||||||
type: 'readonly'
|
type: 'readonly',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cleanUpContents = (contents) => {
|
export const cleanUpContents = (contents) => {
|
||||||
let filteredContents = contents
|
let filteredContents = contents.filter(chooserFilter); // only use items that are not chooser elements
|
||||||
.filter(chooserFilter); // only use items that are not chooser elements
|
|
||||||
|
|
||||||
return filteredContents.map(content => {
|
return filteredContents.map((content) => {
|
||||||
// if the element has a contents property, it's a list of contents, filter them
|
// if the element has a contents property, it's a list of contents, filter them
|
||||||
if (content.contents) {
|
if (content.contents) {
|
||||||
return {
|
return {
|
||||||
...content,
|
...content,
|
||||||
contents: content.contents.filter(chooserFilter)
|
contents: content.contents.filter(chooserFilter),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// else just return it
|
// else just return it
|
||||||
|
|
@ -44,16 +51,16 @@ export const cleanUpContents = (contents) => {
|
||||||
// transform value prop to contents, to better handle the input type on the server
|
// transform value prop to contents, to better handle the input type on the server
|
||||||
export const transformInnerContents = (contents) => {
|
export const transformInnerContents = (contents) => {
|
||||||
let ret = [];
|
let ret = [];
|
||||||
for (let content of contents) {
|
for (let content of contents) {
|
||||||
if (Array.isArray(content.value)) {
|
if (Array.isArray(content.value)) {
|
||||||
const {value, ...contentWithoutValue} = content;
|
const { value, ...contentWithoutValue } = content;
|
||||||
ret.push({
|
ret.push({
|
||||||
...contentWithoutValue,
|
...contentWithoutValue,
|
||||||
contents: value
|
contents: value,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ret.push(content);
|
ret.push(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,57 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="{ 'cms-document-block--solution': solution }" class="cms-document-block">
|
||||||
:class="{'cms-document-block--solution': solution}"
|
|
||||||
class="cms-document-block"
|
|
||||||
>
|
|
||||||
<document-icon class="cms-document-block__icon" />
|
<document-icon class="cms-document-block__icon" />
|
||||||
<a
|
<a :href="value.url" class="cms-document-block__link" target="_blank">{{ value.display_text }}</a>
|
||||||
:href="value.url"
|
|
||||||
class="cms-document-block__link"
|
|
||||||
target="_blank"
|
|
||||||
>{{ value.display_text }}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
|
const DocumentIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: Object,
|
value: Object,
|
||||||
solution: {
|
solution: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
DocumentIcon,
|
DocumentIcon,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.cms-document-block {
|
.cms-document-block {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 50px 1fr 50px;
|
grid-template-columns: 50px 1fr 50px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent: &;
|
||||||
|
|
||||||
|
&--solution {
|
||||||
|
margin-bottom: $small-spacing;
|
||||||
|
|
||||||
|
#{$parent}__link {
|
||||||
|
color: $color-silver-dark;
|
||||||
}
|
}
|
||||||
|
#{$parent}__icon {
|
||||||
|
fill: $color-silver-dark;
|
||||||
&__link {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parent: &;
|
|
||||||
|
|
||||||
&--solution {
|
|
||||||
margin-bottom: $small-spacing;
|
|
||||||
|
|
||||||
#{$parent}__link {
|
|
||||||
color: $color-silver-dark;
|
|
||||||
}
|
|
||||||
#{$parent}__icon {
|
|
||||||
fill: $color-silver-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="componentClass" :data-scrollto="component.id" data-cy="content-component">
|
||||||
:class="componentClass"
|
|
||||||
:data-scrollto="component.id"
|
|
||||||
data-cy="content-component"
|
|
||||||
>
|
|
||||||
<bookmark-actions
|
<bookmark-actions
|
||||||
:bookmarked="bookmarked"
|
:bookmarked="bookmarked"
|
||||||
:note="note"
|
:note="note"
|
||||||
|
|
@ -13,96 +9,105 @@
|
||||||
@edit-note="editNote"
|
@edit-note="editNote"
|
||||||
@bookmark="bookmarkContent(component.id, !bookmarked)"
|
@bookmark="bookmarkContent(component.id, !bookmarked)"
|
||||||
/>
|
/>
|
||||||
<component
|
<component v-bind="component" :parent="parent" :is="component.type" />
|
||||||
v-bind="component"
|
|
||||||
:parent="parent"
|
|
||||||
:is="component.type"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {constructContentComponentBookmarkMutation} from '@/helpers/update-content-bookmark-mutation';
|
import { constructContentComponentBookmarkMutation } from '@/helpers/update-content-bookmark-mutation';
|
||||||
|
|
||||||
const TextBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/TextBlock');
|
const TextBlock = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/TextBlock');
|
||||||
const InstrumentWidget = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InstrumentWidget');
|
const InstrumentWidget = () =>
|
||||||
const ImageBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ImageBlock');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/InstrumentWidget');
|
||||||
const ImageUrlBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ImageUrlBlock');
|
const ImageBlock = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ImageBlock');
|
||||||
const VideoBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/VideoBlock');
|
const ImageUrlBlock = () =>
|
||||||
const LinkBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/LinkBlock');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ImageUrlBlock');
|
||||||
const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock');
|
const VideoBlock = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/VideoBlock');
|
||||||
const CmsDocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/CmsDocumentBlock');
|
const LinkBlock = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/LinkBlock');
|
||||||
const InfogramBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InfogramBlock');
|
const DocumentBlock = () =>
|
||||||
const ThinglinkBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ThinglinkBlock');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/DocumentBlock');
|
||||||
const GeniallyBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/GeniallyBlock');
|
const CmsDocumentBlock = () =>
|
||||||
const SubtitleBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/SubtitleBlock');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/CmsDocumentBlock');
|
||||||
const SectionTitleBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/SectionTitleBlock');
|
const InfogramBlock = () =>
|
||||||
const ContentListBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ContentListBlock');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/InfogramBlock');
|
||||||
const ModuleRoomSlug = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ModuleRoomSlug');
|
const ThinglinkBlock = () =>
|
||||||
const Assignment = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/Assignment');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ThinglinkBlock');
|
||||||
const Survey = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/SurveyBlock');
|
const GeniallyBlock = () =>
|
||||||
const Solution = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Solution');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/GeniallyBlock');
|
||||||
const Instruction = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Instruction');
|
const SubtitleBlock = () =>
|
||||||
const BookmarkActions = () => import(/* webpackChunkName: "content-components" */'@/components/notes/BookmarkActions');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/SubtitleBlock');
|
||||||
|
const SectionTitleBlock = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/SectionTitleBlock');
|
||||||
|
const ContentListBlock = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ContentListBlock');
|
||||||
|
const ModuleRoomSlug = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ModuleRoomSlug');
|
||||||
|
const Assignment = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/assignment/Assignment');
|
||||||
|
const Survey = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/SurveyBlock');
|
||||||
|
const Solution = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/Solution');
|
||||||
|
const Instruction = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/Instruction');
|
||||||
|
const BookmarkActions = () => import(/* webpackChunkName: "content-components" */ '@/components/notes/BookmarkActions');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
component: {
|
component: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
parent: {
|
parent: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
bookmarks: {
|
bookmarks: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => ([])
|
default: () => [],
|
||||||
},
|
},
|
||||||
notes: {
|
notes: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => ([])
|
default: () => [],
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: '',
|
||||||
},
|
},
|
||||||
editMode: {
|
editMode: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
'text_block': TextBlock,
|
text_block: TextBlock,
|
||||||
'basic_knowledge': InstrumentWidget, // for legacy
|
basic_knowledge: InstrumentWidget, // for legacy
|
||||||
'instrument': InstrumentWidget,
|
instrument: InstrumentWidget,
|
||||||
'image_block': ImageBlock,
|
image_block: ImageBlock,
|
||||||
'image_url_block': ImageUrlBlock,
|
image_url_block: ImageUrlBlock,
|
||||||
'video_block': VideoBlock,
|
video_block: VideoBlock,
|
||||||
'link_block': LinkBlock,
|
link_block: LinkBlock,
|
||||||
'document_block': DocumentBlock,
|
document_block: DocumentBlock,
|
||||||
'infogram_block': InfogramBlock,
|
infogram_block: InfogramBlock,
|
||||||
'genially_block': GeniallyBlock,
|
genially_block: GeniallyBlock,
|
||||||
'subtitle': SubtitleBlock,
|
subtitle: SubtitleBlock,
|
||||||
'section_title': SectionTitleBlock,
|
section_title: SectionTitleBlock,
|
||||||
'content_list': ContentListBlock,
|
content_list: ContentListBlock,
|
||||||
'module_room_slug': ModuleRoomSlug,
|
module_room_slug: ModuleRoomSlug,
|
||||||
'thinglink_block': ThinglinkBlock,
|
thinglink_block: ThinglinkBlock,
|
||||||
'cms_document_block': CmsDocumentBlock,
|
cms_document_block: CmsDocumentBlock,
|
||||||
Survey,
|
Survey,
|
||||||
Solution,
|
Solution,
|
||||||
Instruction,
|
Instruction,
|
||||||
Assignment,
|
Assignment,
|
||||||
BookmarkActions
|
BookmarkActions,
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
bookmarked() {
|
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() {
|
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;
|
return bookmark && bookmark.note;
|
||||||
},
|
},
|
||||||
showBookmarkActions() {
|
showBookmarkActions() {
|
||||||
|
|
@ -114,18 +119,19 @@ export default {
|
||||||
classes.push('content-component--bookmarked');
|
classes.push('content-component--bookmarked');
|
||||||
}
|
}
|
||||||
return classes;
|
return classes;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
addNote(id) {
|
addNote(id) {
|
||||||
const type = Object.prototype.hasOwnProperty.call(this.parent, '__typename')
|
const type = Object.prototype.hasOwnProperty.call(this.parent, '__typename')
|
||||||
? this.parent.__typename : 'ContentBlockNode';
|
? this.parent.__typename
|
||||||
|
: 'ContentBlockNode';
|
||||||
|
|
||||||
this.$store.dispatch('addNote', {
|
this.$store.dispatch('addNote', {
|
||||||
content: id,
|
content: id,
|
||||||
type,
|
type,
|
||||||
block: this.root
|
block: this.root,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
editNote() {
|
editNote() {
|
||||||
|
|
@ -133,37 +139,36 @@ export default {
|
||||||
},
|
},
|
||||||
bookmarkContent(uuid, bookmarked) {
|
bookmarkContent(uuid, bookmarked) {
|
||||||
this.$apollo.mutate(constructContentComponentBookmarkMutation(uuid, bookmarked, this.parent, this.root));
|
this.$apollo.mutate(constructContentComponentBookmarkMutation(uuid, bookmarked, this.parent, this.root));
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-component {
|
.content-component {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&--bookmarked {
|
&--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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ol class="content-list">
|
<ol class="content-list">
|
||||||
<li
|
<li class="content-list__item" v-for="(item, index) in items" :key="item.id">
|
||||||
class="content-list__item"
|
<slot :item="item" :index="index">
|
||||||
v-for="(item, index) in items"
|
|
||||||
:key="item.id"
|
|
||||||
>
|
|
||||||
<slot
|
|
||||||
:item="item"
|
|
||||||
:index="index"
|
|
||||||
>
|
|
||||||
{{ item.id }}
|
{{ item.id }}
|
||||||
</slot>
|
</slot>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -16,13 +9,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
//
|
//
|
||||||
props: {
|
props: {
|
||||||
items: {
|
items: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => ([])
|
default: () => [],
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<content-list
|
<content-list :items="contentBlocks">
|
||||||
:items="contentBlocks"
|
|
||||||
>
|
|
||||||
<template #default="{ item }">
|
<template #default="{ item }">
|
||||||
<content-block
|
<content-block :content-block="item" :parent="parent" />
|
||||||
:content-block="item"
|
|
||||||
:parent="parent"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</content-list>
|
</content-list>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ContentList from '@/components/content-blocks/ContentList.vue';
|
import ContentList from '@/components/content-blocks/ContentList.vue';
|
||||||
export default {
|
export default {
|
||||||
name: 'ContentBlockList',
|
name: 'ContentBlockList',
|
||||||
props: ['contents', 'parent'],
|
props: ['contents', 'parent'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ContentList,
|
ContentList,
|
||||||
// https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
// https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
||||||
ContentBlock: () => import('@/components/ContentBlock.vue')
|
ContentBlock: () => import('@/components/ContentBlock.vue'),
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
contentBlocks() {
|
contentBlocks() {
|
||||||
return this.contents.map(contentBlock => {
|
return this.contents.map((contentBlock) => {
|
||||||
const contents = contentBlock.value ? [...contentBlock.value] : [];
|
const contents = contentBlock.value ? [...contentBlock.value] : [];
|
||||||
return Object.assign({}, contentBlock, {
|
return Object.assign({}, contentBlock, {
|
||||||
contents,
|
contents,
|
||||||
indent: true,
|
indent: true,
|
||||||
bookmarks: this.parent.bookmarks,
|
bookmarks: this.parent.bookmarks,
|
||||||
notes: this.parent.notes,
|
notes: this.parent.notes,
|
||||||
root: this.parent.id
|
root: this.parent.id,
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,71 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="document-block">
|
<div class="document-block">
|
||||||
<document-icon class="document-block__icon" />
|
<document-icon class="document-block__icon" />
|
||||||
<a
|
<a :href="value.url" class="document-block__link" target="_blank">{{ urlName }}</a>
|
||||||
:href="value.url"
|
<a class="document-block__remove" v-if="showTrashIcon" @click="$emit('trash')">
|
||||||
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" />
|
<trash-icon class="document-block__trash-icon" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
|
const DocumentIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon');
|
||||||
const TrashIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon');
|
const TrashIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/TrashIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: Object,
|
value: Object,
|
||||||
showTrashIcon: Boolean,
|
showTrashIcon: Boolean,
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
DocumentIcon,
|
DocumentIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
urlName: function() {
|
urlName: function () {
|
||||||
if (this.value && this.value.url) {
|
if (this.value && this.value.url) {
|
||||||
const parts = this.value.url.split('/');
|
const parts = this.value.url.split('/');
|
||||||
return parts[parts.length - 1];
|
return parts[parts.length - 1];
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
};
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.document-block {
|
.document-block {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 50px 1fr 50px;
|
grid-template-columns: 50px 1fr 50px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -18,51 +18,51 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
src() {
|
src() {
|
||||||
return `https://view.genial.ly/${this.value.id}`;
|
return `https://view.genial.ly/${this.value.id}`;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
openFullscreen() {
|
openFullscreen() {
|
||||||
this.$store.dispatch('showFullscreenInfographic', {
|
this.$store.dispatch('showFullscreenInfographic', {
|
||||||
id: this.value.id,
|
id: this.value.id,
|
||||||
type: 'genially-block'
|
type: 'genially-block',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
// Styling and structure taken from original iframe
|
// Styling and structure taken from original iframe
|
||||||
.genially-block {
|
.genially-block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
&__wrapper {
|
&__wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 75%;
|
padding-bottom: 75%;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
|
||||||
|
|
||||||
&__iframe {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<img
|
<img :src="value.path" alt="" class="image-block" @click="openFullscreen" />
|
||||||
:src="value.path"
|
|
||||||
alt=""
|
|
||||||
class="image-block"
|
|
||||||
@click="openFullscreen"
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
methods: {
|
methods: {
|
||||||
openFullscreen() {
|
openFullscreen() {
|
||||||
this.$store.dispatch('showFullscreenImage', this.value.path);
|
this.$store.dispatch('showFullscreenImage', this.value.path);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.image-block {
|
.image-block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
border-radius: 13px;
|
border-radius: 13px;
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<img
|
<img :src="value.url" alt="" class="image-block" @click="openFullscreen" />
|
||||||
:src="value.url"
|
|
||||||
alt=""
|
|
||||||
class="image-block"
|
|
||||||
@click="openFullscreen"
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
methods: {
|
methods: {
|
||||||
openFullscreen() {
|
openFullscreen() {
|
||||||
this.$store.dispatch('showFullscreenImage', this.value.url);
|
this.$store.dispatch('showFullscreenImage', this.value.url);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.image-block {
|
.image-block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
border-radius: 13px;
|
border-radius: 13px;
|
||||||
|
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -7,79 +7,79 @@
|
||||||
class="infogram-block__iframe"
|
class="infogram-block__iframe"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
style="border:none;"
|
style="border: none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
height: 1
|
height: 1,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
src() {
|
||||||
|
return `https://e.infogram.com/${this.id}?src=embed`;
|
||||||
},
|
},
|
||||||
|
href() {
|
||||||
computed: {
|
return `https://infogram.com/${this.id}`;
|
||||||
src() {
|
|
||||||
return `https://e.infogram.com/${this.id}?src=embed`;
|
|
||||||
},
|
|
||||||
href() {
|
|
||||||
return `https://infogram.com/${this.id}`;
|
|
||||||
},
|
|
||||||
id() {
|
|
||||||
return this.value.id;
|
|
||||||
},
|
|
||||||
title() {
|
|
||||||
return this.value.title || 'Infografik';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
id() {
|
||||||
|
return this.value.id;
|
||||||
|
},
|
||||||
|
title() {
|
||||||
|
return this.value.title || 'Infografik';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// from https://developers.infogr.am/oembed/
|
// from https://developers.infogr.am/oembed/
|
||||||
window.addEventListener('message', event => {
|
window.addEventListener('message', (event) => {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
if (data.context === 'iframe.resize' && this.parseId(data.src) === this.id) {
|
if (data.context === 'iframe.resize' && this.parseId(data.src) === this.id) {
|
||||||
this.height = data.height;
|
this.height = data.height;
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
parseId(src) {
|
||||||
|
// src will be in the format of something like https://e.infogram.com/0ccf86bc-1afe-4026-b313-1f1b5992452b?src=embed
|
||||||
|
let last = src.split('/').pop();
|
||||||
|
return last.substring(0, last.indexOf('?')); // we're only interested in the id part before the '?'
|
||||||
|
},
|
||||||
|
openFullscreen() {
|
||||||
|
this.$store.dispatch('showFullscreenInfographic', {
|
||||||
|
id: this.value.id,
|
||||||
|
type: 'infogram-block',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
},
|
||||||
methods: {
|
};
|
||||||
parseId(src) {
|
|
||||||
// src will be in the format of something like https://e.infogram.com/0ccf86bc-1afe-4026-b313-1f1b5992452b?src=embed
|
|
||||||
let last = src.split('/').pop();
|
|
||||||
return last.substring(0, last.indexOf('?')); // we're only interested in the id part before the '?'
|
|
||||||
},
|
|
||||||
openFullscreen() {
|
|
||||||
this.$store.dispatch('showFullscreenInfographic', {
|
|
||||||
id: this.value.id,
|
|
||||||
type: 'infogram-block'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.infogram-block {
|
.infogram-block {
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
&__link {
|
&__link {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
|
||||||
|
|
||||||
&__iframe {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__iframe {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,50 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="instruction" v-if="me.isTeacher">
|
||||||
class="instruction"
|
|
||||||
v-if="me.isTeacher"
|
|
||||||
>
|
|
||||||
<bulb-icon class="instruction__icon" />
|
<bulb-icon class="instruction__icon" />
|
||||||
<a
|
<a :href="url" class="instruction__link">{{ text }}</a>
|
||||||
:href="url"
|
|
||||||
class="instruction__link"
|
|
||||||
>{{ text }}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
const BulbIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/BulbIcon');
|
const BulbIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
mixins: [me],
|
mixins: [me],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
BulbIcon
|
BulbIcon,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
text() {
|
||||||
|
return this.value.text ? this.value.text : 'Anweisungen';
|
||||||
},
|
},
|
||||||
|
url() {
|
||||||
computed: {
|
return this.value.document ? this.value.document.url : this.value.url;
|
||||||
text() {
|
},
|
||||||
return this.value.text ? this.value.text : 'Anweisungen';
|
},
|
||||||
},
|
};
|
||||||
url() {
|
|
||||||
return this.value.document ? this.value.document.url : this.value.url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.instruction {
|
.instruction {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
margin-right: $small-spacing;
|
margin-right: $small-spacing;
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
@include heading-3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
@include heading-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="instrument-widget">
|
<div class="instrument-widget">
|
||||||
<div
|
<div class="instrument-widget__description" v-html="value.description" />
|
||||||
class="instrument-widget__description"
|
|
||||||
v-html="value.description"
|
|
||||||
/>
|
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'instrument', params: { slug: value.slug }}"
|
:to="{ name: 'instrument', params: { slug: value.slug } }"
|
||||||
class="instrument-widget__button button"
|
class="instrument-widget__button button"
|
||||||
:style="{
|
:style="{
|
||||||
borderColor: value.foreground
|
borderColor: value.foreground,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ $flavor.textInstrument }} anzeigen
|
{{ $flavor.textInstrument }} anzeigen
|
||||||
|
|
@ -18,24 +15,23 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// 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
|
// 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
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/_variables.scss";
|
@import '~styles/_variables.scss';
|
||||||
|
|
||||||
.instrument-widget {
|
.instrument-widget {
|
||||||
margin-bottom: $small-spacing;
|
margin-bottom: $small-spacing;
|
||||||
|
|
||||||
&__description {
|
&__description {
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px;
|
||||||
}
|
|
||||||
|
|
||||||
&__button {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,52 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="{ 'link-block--no-margin': noMargin }" class="link-block">
|
||||||
:class="{ 'link-block--no-margin': noMargin}"
|
|
||||||
class="link-block"
|
|
||||||
>
|
|
||||||
<link-icon class="link-block__icon" />
|
<link-icon class="link-block__icon" />
|
||||||
<a
|
<a :href="href" class="link-block__link" target="_blank">{{ value.text }}</a>
|
||||||
:href="href"
|
|
||||||
class="link-block__link"
|
|
||||||
target="_blank"
|
|
||||||
>{{ value.text }}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const LinkIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/LinkIcon');
|
const LinkIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/LinkIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: Object,
|
value: Object,
|
||||||
noMargin: {
|
noMargin: {
|
||||||
default: false
|
default: false,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
LinkIcon
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.link-block {
|
.link-block {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 50px 1fr;
|
grid-template-columns: 50px 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&--no-margin {
|
&--no-margin {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="module-slug">
|
<div class="module-slug">
|
||||||
<router-link
|
<router-link :to="{ name: 'moduleRoom', params: { slug: value.slug } }" class="button button--primary">
|
||||||
:to="{name: 'moduleRoom', params: { slug: value.slug }}"
|
|
||||||
class="button button--primary"
|
|
||||||
>
|
|
||||||
Raum anzeigen
|
Raum anzeigen
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value']
|
props: ['value'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.module-slug {
|
.module-slug {
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<h4
|
<h4 class="section-title" v-html="value.text" />
|
||||||
class="section-title"
|
|
||||||
v-html="value.text"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value']
|
props: ['value'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
@include heading-line-height;
|
@include heading-line-height;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,114 +1,95 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div
|
<div class="solution" data-cy="solution">
|
||||||
class="solution"
|
<a class="solution__toggle" data-cy="show-solution" @click="toggle"
|
||||||
data-cy="solution"
|
>Lösung
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="solution__toggle"
|
|
||||||
data-cy="show-solution"
|
|
||||||
@click="toggle"
|
|
||||||
>Lösung
|
|
||||||
<template v-if="!visible">anzeigen</template>
|
<template v-if="!visible">anzeigen</template>
|
||||||
<template v-else>ausblenden</template>
|
<template v-else>ausblenden</template>
|
||||||
</a>
|
</a>
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div
|
<div class="solution__hidden fade" v-if="visible">
|
||||||
class="solution__hidden fade"
|
<p class="solution__text solution-text" data-cy="solution-text" v-html="sanitizedText" />
|
||||||
v-if="visible"
|
<cms-document-block :solution="true" class="solution__document" :value="value.document" v-if="value.document" />
|
||||||
>
|
|
||||||
<p
|
|
||||||
class="solution__text solution-text"
|
|
||||||
data-cy="solution-text"
|
|
||||||
|
|
||||||
v-html="sanitizedText"
|
|
||||||
/>
|
|
||||||
<cms-document-block
|
|
||||||
:solution="true"
|
|
||||||
class="solution__document"
|
|
||||||
:value="value.document"
|
|
||||||
v-if="value.document"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {sanitizeAsHtml} from '@/helpers/text';
|
import { sanitizeAsHtml } from '@/helpers/text';
|
||||||
import CmsDocumentBlock from '@/components/content-blocks/CmsDocumentBlock';
|
import CmsDocumentBlock from '@/components/content-blocks/CmsDocumentBlock';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
components: {CmsDocumentBlock},
|
components: { CmsDocumentBlock },
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visible: false,
|
visible: false,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
sanitizedText() {
|
||||||
|
return sanitizeAsHtml(this.value.text);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
methods: {
|
||||||
sanitizedText() {
|
toggle() {
|
||||||
return sanitizeAsHtml(this.value.text);
|
this.visible = !this.visible;
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
methods: {
|
};
|
||||||
toggle() {
|
|
||||||
this.visible = !this.visible;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.solution {
|
.solution {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-rows: auto;
|
grid-auto-rows: auto;
|
||||||
grid-row-gap: 15px;
|
grid-row-gap: 15px;
|
||||||
|
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
&__toggle {
|
&__toggle {
|
||||||
font-family: $sans-serif-font-family;
|
font-family: $sans-serif-font-family;
|
||||||
color: $color-silver-dark;
|
color: $color-silver-dark;
|
||||||
font-size: toRem(15px);
|
font-size: toRem(15px);
|
||||||
/*margin-bottom: 15px;*/
|
/*margin-bottom: 15px;*/
|
||||||
display: block;
|
display: block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: $font-weight-regular;
|
font-weight: $font-weight-regular;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__text {
|
&__text {
|
||||||
|
font-size: toRem(18px);
|
||||||
|
color: $color-silver-dark;
|
||||||
|
|
||||||
|
:deep(p) {
|
||||||
font-size: toRem(18px);
|
font-size: toRem(18px);
|
||||||
color: $color-silver-dark;
|
color: $color-silver-dark;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(p) {
|
:deep(ul) {
|
||||||
font-size: toRem(18px);
|
padding-left: $medium-spacing;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
list-style: disc outside none;
|
||||||
color: $color-silver-dark;
|
color: $color-silver-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(ul) {
|
|
||||||
padding-left: $medium-spacing;
|
|
||||||
|
|
||||||
> li {
|
|
||||||
list-style: disc outside none;
|
|
||||||
color: $color-silver-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
transition: opacity .3s;
|
transition: opacity 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter,
|
.fade-enter,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<h5
|
<h5 class="subtitle" data-cy="subtitle-block" v-html="sanitizedText" />
|
||||||
class="subtitle"
|
|
||||||
data-cy="subtitle-block"
|
|
||||||
v-html="sanitizedText"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {sanitize} from '@/helpers/text';
|
import { sanitize } from '@/helpers/text';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
sanitizedText() {
|
sanitizedText() {
|
||||||
return sanitize(this.value.text);
|
return sanitize(this.value.text);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
margin-bottom: $medium-spacing;
|
margin-bottom: $medium-spacing;
|
||||||
margin-bottom: calc(#{$large-spacing} - 0.1rem);
|
margin-bottom: calc(#{$large-spacing} - 0.1rem);
|
||||||
@include heading-line-height;
|
@include heading-line-height;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :data-scrollto="value.id" class="survey-block">
|
||||||
:data-scrollto="value.id"
|
<router-link :to="{ name: 'survey', params: { id: value.id } }" class="button button--primary">
|
||||||
class="survey-block"
|
|
||||||
>
|
|
||||||
<router-link
|
|
||||||
:to="{name: 'survey', params: {id:value.id}}"
|
|
||||||
class="button button--primary"
|
|
||||||
>
|
|
||||||
Übung anzeigen
|
Übung anzeigen
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.survey-block {
|
.survey-block {
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="task">
|
<div class="task">
|
||||||
<div
|
<div class="task__text" v-html="value.text" />
|
||||||
class="task__text"
|
|
||||||
v-html="value.text"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value']
|
props: ['value'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
.task {
|
.task {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
background-color: $color-brand-light;
|
background-color: $color-brand-light;
|
||||||
border-radius: $default-border-radius;
|
border-radius: $default-border-radius;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,35 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div
|
<div class="text-block" data-cy="text-block" v-html="sanitizedText" />
|
||||||
class="text-block"
|
|
||||||
data-cy="text-block"
|
|
||||||
v-html="sanitizedText"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
sanitizedText() {
|
sanitizedText() {
|
||||||
// don't need to sanitize the input, server does this
|
// don't need to sanitize the input, server does this
|
||||||
return this.value.text;
|
return this.value.text;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.text-block {
|
.text-block {
|
||||||
margin-bottom: $medium-spacing; // if calc is not supported
|
margin-bottom: $medium-spacing; // if calc is not supported
|
||||||
margin-bottom: calc(#{$large-spacing} - 0.25rem); // to offset the 1.5 line height, which leaves a padding
|
margin-bottom: calc(#{$large-spacing} - 0.25rem); // to offset the 1.5 line height, which leaves a padding
|
||||||
@include regular-paragraph;
|
@include regular-paragraph;
|
||||||
|
|
||||||
:deep(ul) {
|
:deep(ul) {
|
||||||
@include list-parent;
|
@include list-parent;
|
||||||
}
|
|
||||||
|
|
||||||
:deep(li) {
|
|
||||||
@include list-child;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(li) {
|
||||||
|
@include list-child;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -20,51 +20,51 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
src() {
|
src() {
|
||||||
return `https://www.thinglink.com/card/${this.value.id}`;
|
return `https://www.thinglink.com/card/${this.value.id}`;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
openFullscreen() {
|
openFullscreen() {
|
||||||
this.$store.dispatch('showFullscreenInfographic', {
|
this.$store.dispatch('showFullscreenInfographic', {
|
||||||
id: this.value.id,
|
id: this.value.id,
|
||||||
type: 'thinglink-block'
|
type: 'thinglink-block',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
|
|
||||||
// Styling and structure taken from original iframe
|
// Styling and structure taken from original iframe
|
||||||
.thinglink-block {
|
.thinglink-block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: $large-spacing;
|
margin-bottom: $large-spacing;
|
||||||
|
|
||||||
&__wrapper {
|
&__wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 75%;
|
padding-bottom: 75%;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
|
||||||
|
|
||||||
&__iframe {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,42 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="video-block">
|
<div class="video-block">
|
||||||
<youtube-embed
|
<youtube-embed :url="value.url" v-if="isYoutube" />
|
||||||
:url="value.url"
|
<vimeo-embed :url="value.url" v-if="isVimeo" />
|
||||||
v-if="isYoutube"
|
<srf-embed :url="value.url" v-if="isSrf" />
|
||||||
/>
|
|
||||||
<vimeo-embed
|
|
||||||
:url="value.url"
|
|
||||||
v-if="isVimeo"
|
|
||||||
/>
|
|
||||||
<srf-embed
|
|
||||||
:url="value.url"
|
|
||||||
v-if="isSrf"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
||||||
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
||||||
import SrfEmbed from '@/components/videos/SrfEmbed';
|
import SrfEmbed from '@/components/videos/SrfEmbed';
|
||||||
import {isVimeoUrl, isYoutubeUrl, isSrfUrl} from '@/helpers/video';
|
import { isVimeoUrl, isYoutubeUrl, isSrfUrl } from '@/helpers/video';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
YoutubeEmbed,
|
YoutubeEmbed,
|
||||||
VimeoEmbed,
|
VimeoEmbed,
|
||||||
SrfEmbed
|
SrfEmbed,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isYoutube() {
|
||||||
|
return isYoutubeUrl(this.value.url);
|
||||||
},
|
},
|
||||||
|
isVimeo() {
|
||||||
computed: {
|
return isVimeoUrl(this.value.url);
|
||||||
isYoutube() {
|
},
|
||||||
return isYoutubeUrl(this.value.url);
|
isSrf() {
|
||||||
},
|
return isSrfUrl(this.value.url);
|
||||||
isVimeo() {
|
},
|
||||||
return isVimeoUrl(this.value.url);
|
},
|
||||||
},
|
};
|
||||||
isSrf() {
|
|
||||||
return isSrfUrl(this.value.url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.video-block {
|
.video-block {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div
|
<div :data-scrollto="value.id" class="assignment">
|
||||||
:data-scrollto="value.id"
|
<p class="assignment__main-text" data-cy="assignment-main-text" v-html="assignment.assignment" />
|
||||||
class="assignment"
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
class="assignment__main-text"
|
|
||||||
data-cy="assignment-main-text"
|
|
||||||
v-html="assignment.assignment"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<solution
|
<solution :value="solution" v-if="assignment.solution" />
|
||||||
:value="solution"
|
|
||||||
v-if="assignment.solution"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template v-if="isStudent">
|
<template v-if="isStudent">
|
||||||
<submission-form
|
<submission-form
|
||||||
|
|
@ -33,100 +23,92 @@
|
||||||
@spellcheck="spellcheck"
|
@spellcheck="spellcheck"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<spell-check
|
<spell-check :corrections="corrections" :text="submission.text" />
|
||||||
:corrections="corrections"
|
|
||||||
:text="submission.text"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<p
|
<p class="assignment__feedback" v-if="assignment.submission.submissionFeedback" v-html="feedbackText" />
|
||||||
class="assignment__feedback"
|
|
||||||
v-if="assignment.submission.submissionFeedback"
|
|
||||||
v-html="feedbackText"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!isStudent">
|
<template v-if="!isStudent">
|
||||||
<router-link
|
<router-link :to="{ name: 'submissions', params: { id: assignment.id } }" class="button button--primary">
|
||||||
:to="{name: 'submissions', params: { id: assignment.id }}"
|
Zu den Ergebnissen
|
||||||
class="button button--primary"
|
|
||||||
>
|
|
||||||
Zu den
|
|
||||||
Ergebnissen
|
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapActions, mapGetters} from 'vuex';
|
import { mapActions, mapGetters } from 'vuex';
|
||||||
import ASSIGNMENT_QUERY from '@/graphql/gql/queries/assignmentQuery.gql';
|
import ASSIGNMENT_QUERY from '@/graphql/gql/queries/assignmentQuery.gql';
|
||||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||||
import UPDATE_ASSIGNMENT_MUTATION from '@/graphql/gql/mutations/updateAssignmentMutation.gql';
|
import UPDATE_ASSIGNMENT_MUTATION from '@/graphql/gql/mutations/updateAssignmentMutation.gql';
|
||||||
import UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS from '@/graphql/gql/mutations/updateAssignmentMutationWithSuccess.gql';
|
import UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS from '@/graphql/gql/mutations/updateAssignmentMutationWithSuccess.gql';
|
||||||
import SPELL_CHECK_MUTATION from '@/graphql/gql/mutations/spellCheck.gql';
|
import SPELL_CHECK_MUTATION from '@/graphql/gql/mutations/spellCheck.gql';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import {sanitize} from '@/helpers/text';
|
import { sanitize } from '@/helpers/text';
|
||||||
|
|
||||||
const SubmissionForm = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/SubmissionForm');
|
const SubmissionForm = () =>
|
||||||
const Solution = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Solution');
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/assignment/SubmissionForm');
|
||||||
const SpellCheck = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/SpellCheck');
|
const Solution = () => import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/Solution');
|
||||||
|
const SpellCheck = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/assignment/SpellCheck');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Solution,
|
Solution,
|
||||||
SubmissionForm,
|
SubmissionForm,
|
||||||
SpellCheck,
|
SpellCheck,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
assignment: {
|
||||||
|
submission: this.initialSubmission(),
|
||||||
|
},
|
||||||
|
me: {
|
||||||
|
permissions: [],
|
||||||
|
},
|
||||||
|
inputType: 'text',
|
||||||
|
unsaved: false,
|
||||||
|
saving: 0,
|
||||||
|
corrections: '',
|
||||||
|
spellcheckLoading: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['scrollToAssignmentId']),
|
||||||
|
final() {
|
||||||
|
return !!this.submission && this.submission.final;
|
||||||
},
|
},
|
||||||
|
submission() {
|
||||||
data() {
|
return this.assignment.submission ? this.assignment.submission : {};
|
||||||
|
},
|
||||||
|
isStudent() {
|
||||||
|
return !this.me.permissions.includes('users.can_manage_school_class_content');
|
||||||
|
},
|
||||||
|
solution() {
|
||||||
return {
|
return {
|
||||||
assignment: {
|
text: this.assignment.solution,
|
||||||
submission: this.initialSubmission(),
|
|
||||||
},
|
|
||||||
me: {
|
|
||||||
permissions: [],
|
|
||||||
},
|
|
||||||
inputType: 'text',
|
|
||||||
unsaved: false,
|
|
||||||
saving: 0,
|
|
||||||
corrections: '',
|
|
||||||
spellcheckLoading: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
id() {
|
||||||
computed: {
|
return this.assignment.id ? this.assignment.id.replace(/=/g, '') : '';
|
||||||
...mapGetters(['scrollToAssignmentId']),
|
|
||||||
final() {
|
|
||||||
return !!this.submission && this.submission.final;
|
|
||||||
},
|
|
||||||
submission() {
|
|
||||||
return this.assignment.submission ? this.assignment.submission : {};
|
|
||||||
},
|
|
||||||
isStudent() {
|
|
||||||
return !this.me.permissions.includes('users.can_manage_school_class_content');
|
|
||||||
},
|
|
||||||
solution() {
|
|
||||||
return {
|
|
||||||
text: this.assignment.solution,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
id() {
|
|
||||||
return this.assignment.id ? this.assignment.id.replace(/=/g, '') : '';
|
|
||||||
},
|
|
||||||
feedbackText() {
|
|
||||||
let feedback = this.assignment.submission.submissionFeedback;
|
|
||||||
let sanitizedFeedbackText = sanitize(feedback.text);
|
|
||||||
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${sanitizedFeedbackText}`;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
feedbackText() {
|
||||||
|
let feedback = this.assignment.submission.submissionFeedback;
|
||||||
|
let sanitizedFeedbackText = sanitize(feedback.text);
|
||||||
|
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${sanitizedFeedbackText}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['scrollToAssignmentReady']),
|
...mapActions(['scrollToAssignmentReady']),
|
||||||
_save: debounce(function (submission) {
|
_save: debounce(function (submission) {
|
||||||
this.saving++;
|
this.saving++;
|
||||||
this.$apollo.mutate({
|
this.$apollo
|
||||||
|
.mutate({
|
||||||
mutation: UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS,
|
mutation: UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -137,7 +119,14 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update(store, {data: {updateAssignment: {successful, updatedAssignment}}}) {
|
update(
|
||||||
|
store,
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
updateAssignment: { successful, updatedAssignment },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
if (successful) {
|
if (successful) {
|
||||||
const query = ASSIGNMENT_QUERY;
|
const query = ASSIGNMENT_QUERY;
|
||||||
|
|
@ -148,80 +137,82 @@
|
||||||
submission,
|
submission,
|
||||||
});
|
});
|
||||||
const data = {
|
const data = {
|
||||||
assignment
|
assignment,
|
||||||
};
|
};
|
||||||
store.writeQuery({query, variables, data});
|
store.writeQuery({ query, variables, data });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
|
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}).then(() => {
|
})
|
||||||
|
.then(() => {
|
||||||
this.saving--;
|
this.saving--;
|
||||||
if (this.saving === 0) {
|
if (this.saving === 0) {
|
||||||
this.unsaved = false;
|
this.unsaved = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 500),
|
}, 500),
|
||||||
saveInput: function (answer) {
|
saveInput: function (answer) {
|
||||||
// reset corrections on input
|
// reset corrections on input
|
||||||
this.corrections = '';
|
this.corrections = '';
|
||||||
this.unsaved = true;
|
this.unsaved = true;
|
||||||
/*
|
/*
|
||||||
We update the assignment on this component, so the changes are reflected on it. The server does not return
|
We update the assignment on this component, so the changes are reflected on it. The server does not return
|
||||||
the updated entity, to prevent the UI to update when the user is entering his input
|
the updated entity, to prevent the UI to update when the user is entering his input
|
||||||
*/
|
*/
|
||||||
this.assignment.submission.text = answer;
|
this.assignment.submission.text = answer;
|
||||||
this._save(this.assignment.submission);
|
this._save(this.assignment.submission);
|
||||||
},
|
},
|
||||||
changeDocumentUrl(documentUrl) {
|
changeDocumentUrl(documentUrl) {
|
||||||
this.assignment.submission.document = documentUrl;
|
this.assignment.submission.document = documentUrl;
|
||||||
this._save(this.assignment.submission);
|
this._save(this.assignment.submission);
|
||||||
},
|
},
|
||||||
turnIn() {
|
turnIn() {
|
||||||
// reset corrections on turn in
|
// reset corrections on turn in
|
||||||
this.corrections = '';
|
this.corrections = '';
|
||||||
this.$apollo.mutate({
|
this.$apollo.mutate({
|
||||||
mutation: UPDATE_ASSIGNMENT_MUTATION,
|
mutation: UPDATE_ASSIGNMENT_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
assignment: {
|
assignment: {
|
||||||
id: this.assignment.id,
|
id: this.assignment.id,
|
||||||
answer: this.assignment.submission.text,
|
answer: this.assignment.submission.text,
|
||||||
document: this.assignment.submission.document,
|
document: this.assignment.submission.document,
|
||||||
final: true,
|
final: true,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
},
|
});
|
||||||
reopen() {
|
},
|
||||||
this.$apollo.mutate({
|
reopen() {
|
||||||
mutation: UPDATE_ASSIGNMENT_MUTATION,
|
this.$apollo.mutate({
|
||||||
variables: {
|
mutation: UPDATE_ASSIGNMENT_MUTATION,
|
||||||
input: {
|
variables: {
|
||||||
assignment: {
|
input: {
|
||||||
id: this.assignment.id,
|
assignment: {
|
||||||
answer: this.assignment.submission.text,
|
id: this.assignment.id,
|
||||||
document: this.assignment.submission.document,
|
answer: this.assignment.submission.text,
|
||||||
final: false,
|
document: this.assignment.submission.document,
|
||||||
},
|
final: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
},
|
});
|
||||||
initialSubmission() {
|
},
|
||||||
return {
|
initialSubmission() {
|
||||||
text: '',
|
return {
|
||||||
document: '',
|
text: '',
|
||||||
final: false,
|
document: '',
|
||||||
};
|
final: false,
|
||||||
},
|
};
|
||||||
spellcheck() {
|
},
|
||||||
let self = this;
|
spellcheck() {
|
||||||
this.spellcheckLoading = true;
|
let self = this;
|
||||||
this.$apollo.mutate({
|
this.spellcheckLoading = true;
|
||||||
|
this.$apollo
|
||||||
|
.mutate({
|
||||||
mutation: SPELL_CHECK_MUTATION,
|
mutation: SPELL_CHECK_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -229,90 +220,96 @@
|
||||||
text: this.assignment.submission.text,
|
text: this.assignment.submission.text,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update(store, {data: {spellCheck: {results}}}) {
|
update(
|
||||||
|
store,
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
spellCheck: { results },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
) {
|
||||||
self.corrections = results;
|
self.corrections = results;
|
||||||
},
|
},
|
||||||
}).then(() => {
|
})
|
||||||
|
.then(() => {
|
||||||
this.spellcheckLoading = false;
|
this.spellcheckLoading = false;
|
||||||
});
|
});
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
assignment: {
|
assignment: {
|
||||||
query: ASSIGNMENT_QUERY,
|
query: ASSIGNMENT_QUERY,
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
id: this.value.id,
|
id: this.value.id,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
result(response) {
|
|
||||||
const data = response.data;
|
|
||||||
this.assignment = cloneDeep(data.assignment);
|
|
||||||
this.assignment.submission = Object.assign(this.initialSubmission(), this.assignment.submission);
|
|
||||||
if (this.assignment.id === this.scrollToAssignmentId && 'stale' in response) {
|
|
||||||
this.$nextTick(() => this.scrollToAssignmentReady(true));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
me: {
|
result(response) {
|
||||||
query: ME_QUERY,
|
const data = response.data;
|
||||||
|
this.assignment = cloneDeep(data.assignment);
|
||||||
|
this.assignment.submission = Object.assign(this.initialSubmission(), this.assignment.submission);
|
||||||
|
if (this.assignment.id === this.scrollToAssignmentId && 'stale' in response) {
|
||||||
|
this.$nextTick(() => this.scrollToAssignmentReady(true));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
me: {
|
||||||
|
query: ME_QUERY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '@/styles/_variables.scss';
|
@import '@/styles/_variables.scss';
|
||||||
@import '@/styles/_functions.scss';
|
@import '@/styles/_functions.scss';
|
||||||
@import '@/styles/_mixins.scss';
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.assignment {
|
.assignment {
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&__title {
|
|
||||||
font-size: toRem(17px);
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__main-text {
|
|
||||||
:deep(ul){
|
|
||||||
@include list-parent
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(li) {
|
|
||||||
@include list-child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__toggle-input-container {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__toggle-input {
|
|
||||||
border: 0;
|
|
||||||
font-family: $sans-serif-font-family;
|
|
||||||
background: transparent;
|
|
||||||
font-size: toRem(14px);
|
|
||||||
padding: 5px 0;
|
|
||||||
margin-right: 15px;
|
|
||||||
outline: 0;
|
|
||||||
color: $color-silver-dark;
|
|
||||||
cursor: pointer;
|
|
||||||
border-bottom: 2px solid transparent;
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
border-bottom-color: $color-charcoal-dark;
|
|
||||||
color: $color-charcoal-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__feedback {
|
|
||||||
@include regular-text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: toRem(17px);
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__main-text {
|
||||||
|
:deep(ul) {
|
||||||
|
@include list-parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(li) {
|
||||||
|
@include list-child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__toggle-input-container {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__toggle-input {
|
||||||
|
border: 0;
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
|
background: transparent;
|
||||||
|
font-size: toRem(14px);
|
||||||
|
padding: 5px 0;
|
||||||
|
margin-right: 15px;
|
||||||
|
outline: 0;
|
||||||
|
color: $color-silver-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
border-bottom-color: $color-charcoal-dark;
|
||||||
|
color: $color-charcoal-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__feedback {
|
||||||
|
@include regular-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,108 +1,99 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="final-submission" data-cy="final-submission">
|
||||||
class="final-submission"
|
<document-block :value="{ url: userInput.document }" class="final-submission__document" v-if="userInput.document" />
|
||||||
data-cy="final-submission"
|
|
||||||
>
|
|
||||||
<document-block
|
|
||||||
:value="{url: userInput.document}"
|
|
||||||
class="final-submission__document"
|
|
||||||
v-if="userInput.document"
|
|
||||||
/>
|
|
||||||
<div class="final-submission__explanation">
|
<div class="final-submission__explanation">
|
||||||
<info-icon class="final-submission__explanation-icon" />
|
<info-icon class="final-submission__explanation-icon" />
|
||||||
<span class="final-submission__explanation-text">{{ sharedMsg }}</span>
|
<span class="final-submission__explanation-text">{{ sharedMsg }}</span>
|
||||||
<a
|
<a class="final-submission__reopen" data-cy="final-submission-reopen" v-if="showReopen" @click="$emit('reopen')"
|
||||||
class="final-submission__reopen"
|
>Bearbeiten</a
|
||||||
data-cy="final-submission-reopen"
|
>
|
||||||
v-if="showReopen"
|
|
||||||
@click="$emit('reopen')"
|
|
||||||
>Bearbeiten</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {newLineToParagraph} from '@/helpers/text';
|
import { newLineToParagraph } from '@/helpers/text';
|
||||||
const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock');
|
const DocumentBlock = () =>
|
||||||
|
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/DocumentBlock');
|
||||||
|
|
||||||
const InfoIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon');
|
const InfoIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
userInput: {
|
userInput: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({}),
|
||||||
},
|
|
||||||
showReopen: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
sharedMsg: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
showReopen: {
|
||||||
components: {
|
type: Boolean,
|
||||||
InfoIcon,
|
default: true,
|
||||||
DocumentBlock,
|
|
||||||
},
|
},
|
||||||
|
sharedMsg: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
components: {
|
||||||
text() {
|
InfoIcon,
|
||||||
return newLineToParagraph(this.userInput.text);
|
DocumentBlock,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
};
|
computed: {
|
||||||
|
text() {
|
||||||
|
return newLineToParagraph(this.userInput.text);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.final-submission {
|
.final-submission {
|
||||||
&__text {
|
&__text {
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
@include input-box-shadow;
|
@include input-box-shadow;
|
||||||
border-radius: $input-border-radius;
|
border-radius: $input-border-radius;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
font-size: toRem(17px);
|
font-size: toRem(17px);
|
||||||
font-family: $sans-serif-font-family;
|
font-family: $sans-serif-font-family;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
font-weight: $font-weight-regular;
|
font-weight: $font-weight-regular;
|
||||||
|
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
hyphens: auto;
|
hyphens: auto;
|
||||||
word-break: break-word;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__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>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,63 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<p
|
<p class="spellcheck" v-if="corrections">
|
||||||
class="spellcheck"
|
|
||||||
v-if="corrections"
|
|
||||||
>
|
|
||||||
<span class="inline-title">Rechtschreibung:</span> <span v-html="highlightedText" />
|
<span class="inline-title">Rechtschreibung:</span> <span v-html="highlightedText" />
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['corrections', 'text'],
|
props: ['corrections', 'text'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
highlightedText() {
|
highlightedText() {
|
||||||
if (!this.corrections) {
|
if (!this.corrections) {
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
let parts = [];
|
|
||||||
let index = 0;
|
|
||||||
[...this.corrections] // no side effects, as sort changes the source array
|
|
||||||
.sort((e1, e2) => (e1.offset + e1.sentenceOffset) - (e2.offset + e2.sentenceOffset))
|
|
||||||
.forEach(current => {
|
|
||||||
let realOffset = current.offset + current.sentenceOffset;
|
|
||||||
parts.push({
|
|
||||||
correct: true,
|
|
||||||
text: this.text.substring(index, realOffset)
|
|
||||||
}, {
|
|
||||||
correct: false,
|
|
||||||
text: this.text.substring(realOffset, realOffset + current.length)
|
|
||||||
});
|
|
||||||
index = realOffset + current.length;
|
|
||||||
});
|
|
||||||
parts.push({
|
|
||||||
correct: true,
|
|
||||||
text: this.text.substring(index, this.text.length + 1)
|
|
||||||
});
|
|
||||||
return parts
|
|
||||||
.filter(part => part.text.length)
|
|
||||||
.reduce((previous, part) => {
|
|
||||||
if (part.correct) {
|
|
||||||
return `${previous}${part.text}`;
|
|
||||||
} else {
|
|
||||||
return `${previous}<span data-cy="spellcheck-correction" class="spellcheck__correction">${part.text}</span>`;
|
|
||||||
}
|
|
||||||
}, '');
|
|
||||||
}
|
}
|
||||||
}
|
let parts = [];
|
||||||
};
|
let index = 0;
|
||||||
|
[...this.corrections] // no side effects, as sort changes the source array
|
||||||
|
.sort((e1, e2) => e1.offset + e1.sentenceOffset - (e2.offset + e2.sentenceOffset))
|
||||||
|
.forEach((current) => {
|
||||||
|
let realOffset = current.offset + current.sentenceOffset;
|
||||||
|
parts.push(
|
||||||
|
{
|
||||||
|
correct: true,
|
||||||
|
text: this.text.substring(index, realOffset),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
correct: false,
|
||||||
|
text: this.text.substring(realOffset, realOffset + current.length),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
index = realOffset + current.length;
|
||||||
|
});
|
||||||
|
parts.push({
|
||||||
|
correct: true,
|
||||||
|
text: this.text.substring(index, this.text.length + 1),
|
||||||
|
});
|
||||||
|
return parts
|
||||||
|
.filter((part) => part.text.length)
|
||||||
|
.reduce((previous, part) => {
|
||||||
|
if (part.correct) {
|
||||||
|
return `${previous}${part.text}`;
|
||||||
|
} else {
|
||||||
|
return `${previous}<span data-cy="spellcheck-correction" class="spellcheck__correction">${part.text}</span>`;
|
||||||
|
}
|
||||||
|
}, '');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "@/styles/_mixins.scss";
|
@import '@/styles/_mixins.scss';
|
||||||
|
|
||||||
.spellcheck {
|
.spellcheck {
|
||||||
@include regular-text;
|
@include regular-text;
|
||||||
|
|
||||||
&__correction {
|
&__correction {
|
||||||
background: yellow;
|
background: yellow;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="submission-form-container__actions" v-if="!isFinalOrReadOnly">
|
||||||
class="submission-form-container__actions"
|
|
||||||
v-if="!isFinalOrReadOnly"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="submission-form-container__submit button button--primary button--white-bg"
|
class="submission-form-container__submit button button--primary button--white-bg"
|
||||||
data-cy="submission-form-submit"
|
data-cy="submission-form-submit"
|
||||||
|
|
@ -29,11 +26,7 @@
|
||||||
>
|
>
|
||||||
{{ spellcheckText }}
|
{{ spellcheckText }}
|
||||||
</button>
|
</button>
|
||||||
<file-upload
|
<file-upload :document="userInput.document" v-if="allowsDocuments" @change-document-url="changeDocumentUrl" />
|
||||||
:document="userInput.document"
|
|
||||||
v-if="allowsDocuments"
|
|
||||||
@change-document-url="changeDocumentUrl"
|
|
||||||
/>
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -48,115 +41,112 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const SubmissionInput = () => import('@/components/content-blocks/assignment/SubmissionInput.vue');
|
const SubmissionInput = () => import('@/components/content-blocks/assignment/SubmissionInput.vue');
|
||||||
const FinalSubmission = () => import('@/components/content-blocks/assignment/FinalSubmission.vue');
|
const FinalSubmission = () => import('@/components/content-blocks/assignment/FinalSubmission.vue');
|
||||||
const FileUpload = () => import('@/components/ui/file-upload/FileUpload.vue');
|
const FileUpload = () => import('@/components/ui/file-upload/FileUpload.vue');
|
||||||
|
|
||||||
|
export default {
|
||||||
export default {
|
props: {
|
||||||
props: {
|
userInput: Object,
|
||||||
userInput: Object,
|
saved: Boolean,
|
||||||
saved: Boolean,
|
placeholder: String,
|
||||||
placeholder: String,
|
action: String,
|
||||||
action: String,
|
reopen: Function,
|
||||||
reopen: Function,
|
document: String,
|
||||||
document: String,
|
readOnly: {
|
||||||
readOnly: {
|
type: Boolean,
|
||||||
type: Boolean,
|
default: false,
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
spellcheck: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
spellcheckLoading: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
sharedMsg: String,
|
|
||||||
},
|
},
|
||||||
|
spellcheck: {
|
||||||
components: {
|
type: Boolean,
|
||||||
FileUpload,
|
default: false,
|
||||||
SubmissionInput,
|
|
||||||
FinalSubmission,
|
|
||||||
},
|
},
|
||||||
|
spellcheckLoading: {
|
||||||
computed: {
|
type: Boolean,
|
||||||
final() {
|
default: false,
|
||||||
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...';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
sharedMsg: String,
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
components: {
|
||||||
reopenSubmission() {
|
FileUpload,
|
||||||
this.$emit('reopen');
|
SubmissionInput,
|
||||||
},
|
FinalSubmission,
|
||||||
saveInput(input) {
|
},
|
||||||
this.$emit('saveInput', input);
|
|
||||||
},
|
computed: {
|
||||||
changeDocumentUrl(documentUrl) {
|
final() {
|
||||||
this.$emit('changeDocumentUrl', documentUrl);
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.submission-form-container {
|
.submission-form-container {
|
||||||
@include form-with-border;
|
@include form-with-border;
|
||||||
|
|
||||||
margin-bottom: $medium-spacing;
|
margin-bottom: $medium-spacing;
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
@include desktop {
|
@include desktop {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__inputs {
|
&__inputs {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__submit {
|
&__submit {
|
||||||
margin-right: $medium-spacing;
|
margin-right: $medium-spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__actions {
|
&__actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__document {
|
&__document {
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__spellcheck {
|
|
||||||
/* so the button does not change size when changing the text */
|
|
||||||
width: 235px;
|
|
||||||
text-align: center;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__spellcheck {
|
||||||
|
/* so the button does not change size when changing the text */
|
||||||
|
width: 235px;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -4,74 +4,68 @@
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:value="inputText"
|
:value="inputText"
|
||||||
:class="{'submission-form__textarea--readonly': readonly}"
|
:class="{ 'submission-form__textarea--readonly': readonly }"
|
||||||
data-cy="submission-textarea"
|
data-cy="submission-textarea"
|
||||||
rows="1"
|
rows="1"
|
||||||
class="submission-form__textarea"
|
class="submission-form__textarea"
|
||||||
v-auto-grow
|
v-auto-grow
|
||||||
@input="$emit('input', $event.target.value)"
|
@input="$emit('input', $event.target.value)"
|
||||||
/>
|
/>
|
||||||
<div
|
<div class="submission-form__save-status submission-form__save-status--saved" v-if="saved">
|
||||||
class="submission-form__save-status submission-form__save-status--saved"
|
|
||||||
v-if="saved"
|
|
||||||
>
|
|
||||||
<tick-circle-icon class="submission-form__save-status-icon" />
|
<tick-circle-icon class="submission-form__save-status-icon" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="submission-form__save-status submission-form__save-status--unsaved" v-if="!saved">
|
||||||
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" />
|
<loading-icon class="submission-form__save-status-icon submission-form__saving-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const TickCircleIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TickCircleIcon');
|
const TickCircleIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/TickCircleIcon');
|
||||||
const LoadingIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/LoadingIcon');
|
const LoadingIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/LoadingIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
inputText: String,
|
inputText: String,
|
||||||
saved: Boolean,
|
saved: Boolean,
|
||||||
readonly: Boolean,
|
readonly: Boolean,
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'Ergebnis erfassen'
|
default: 'Ergebnis erfassen',
|
||||||
}
|
|
||||||
},
|
},
|
||||||
components: {
|
},
|
||||||
TickCircleIcon,
|
components: {
|
||||||
LoadingIcon
|
TickCircleIcon,
|
||||||
}
|
LoadingIcon,
|
||||||
};
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.submission-form {
|
.submission-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
&__textarea {
|
&__textarea {
|
||||||
@include borderless-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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__save-status {
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__save-status-icon {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
fill: $color-silver-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__saving-icon {
|
||||||
|
@include spin;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
class="assignment-form__title skillbox-input"
|
class="assignment-form__title skillbox-input"
|
||||||
placeholder="Aufgabentitel"
|
placeholder="Aufgabentitel"
|
||||||
@input="$emit('assignment-change-title', $event.target.value, index)"
|
@input="$emit('assignment-change-title', $event.target.value, index)"
|
||||||
>
|
/>
|
||||||
<textarea
|
<textarea
|
||||||
:value="value.assignment"
|
:value="value.assignment"
|
||||||
class="assignment-form__exercise-text skillbox-textarea"
|
class="assignment-form__exercise-text skillbox-textarea"
|
||||||
|
|
@ -20,43 +20,43 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const InfoIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon');
|
const InfoIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'index'],
|
props: ['value', 'index'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
InfoIcon
|
InfoIcon,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.assignment-form {
|
.assignment-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-rows: auto;
|
grid-auto-rows: auto;
|
||||||
grid-row-gap: 13px;
|
grid-row-gap: 13px;
|
||||||
grid-template-columns: 40px 1fr;
|
grid-template-columns: 40px 1fr;
|
||||||
grid-column-gap: 16px;
|
grid-column-gap: 16px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
width: $modal-input-width;
|
width: $modal-input-width;
|
||||||
grid-column: span 2;
|
grid-column: span 2;
|
||||||
}
|
|
||||||
|
|
||||||
&__exercise-text {
|
|
||||||
width: $modal-input-width;
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__help-icon {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__help-description {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__exercise-text {
|
||||||
|
width: $modal-input-width;
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__help-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__help-description {
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="['chooser-element', subclass]" :data-cy="cy" @click="$emit('select')">
|
||||||
:class="['chooser-element', subclass]"
|
<component class="chooser-element__icon" :is="icon" />
|
||||||
:data-cy="cy"
|
|
||||||
@click="$emit('select')"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
class="chooser-element__icon"
|
|
||||||
:is="icon"
|
|
||||||
/>
|
|
||||||
<div class="chooser-element__title">
|
<div class="chooser-element__title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -15,62 +8,61 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import formElementIcons from '@/components/ui/form-element-icons';
|
import formElementIcons from '@/components/ui/form-element-icons';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
type: String,
|
type: String,
|
||||||
default() {
|
default() {
|
||||||
return `${this.type}-icon`;
|
return `${this.type}-icon`;
|
||||||
},
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default() {
|
|
||||||
return this.type.replace(/^\w/, c => c.toUpperCase());
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
title: {
|
||||||
components: {
|
type: String,
|
||||||
...formElementIcons,
|
default() {
|
||||||
|
return this.type.replace(/^\w/, (c) => c.toUpperCase());
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
components: {
|
||||||
return {
|
...formElementIcons,
|
||||||
subclass: `chooser-element--${this.type}`,
|
},
|
||||||
cy: `choose-${this.type}-widget`,
|
|
||||||
};
|
data() {
|
||||||
},
|
return {
|
||||||
};
|
subclass: `chooser-element--${this.type}`,
|
||||||
|
cy: `choose-${this.type}-widget`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.chooser-element {
|
.chooser-element {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid $color-silver;
|
border: 1px solid $color-silver;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 105px;
|
height: 105px;
|
||||||
width: 105px;
|
width: 105px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1fr 45px;
|
grid-template-rows: 1fr 45px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
align-self: end;
|
align-self: end;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content-block-element-chooser-widget__wrapper">
|
<div class="content-block-element-chooser-widget__wrapper">
|
||||||
<button
|
<button class="content-block-element-chooser-widget__remove-button icon-button" @click="remove">
|
||||||
class="content-block-element-chooser-widget__remove-button icon-button"
|
|
||||||
@click="remove"
|
|
||||||
>
|
|
||||||
<cross-icon class="icon-button__icon" />
|
<cross-icon class="icon-button__icon" />
|
||||||
</button>
|
</button>
|
||||||
<h3
|
<h3 class="content-block-element-chooser-widget__heading" data-cy="chooser-heading">Neuer Inhalt</h3>
|
||||||
class="content-block-element-chooser-widget__heading"
|
<template v-if="includeListOption && hasDefaultFeatures">
|
||||||
data-cy="chooser-heading"
|
|
||||||
>
|
|
||||||
Neuer Inhalt
|
|
||||||
</h3>
|
|
||||||
<template
|
|
||||||
v-if="includeListOption && hasDefaultFeatures"
|
|
||||||
>
|
|
||||||
<checkbox
|
<checkbox
|
||||||
class="content-block-element-chooser-widget__list-toggle"
|
class="content-block-element-chooser-widget__list-toggle"
|
||||||
:checked="convertToList"
|
:checked="convertToList"
|
||||||
data-cy="convert-to-list-checkbox"
|
data-cy="convert-to-list-checkbox"
|
||||||
label="Aufzählungszeichen hinzufügen"
|
label="Aufzählungszeichen hinzufügen"
|
||||||
@input="convertToList=$event"
|
@input="convertToList = $event"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
:class="{'content-block-element-chooser-widget--no-assignment': hideAssignment}"
|
:class="{ 'content-block-element-chooser-widget--no-assignment': hideAssignment }"
|
||||||
class="content-block-element-chooser-widget"
|
class="content-block-element-chooser-widget"
|
||||||
>
|
>
|
||||||
<chooser-element
|
<chooser-element
|
||||||
|
|
@ -41,182 +31,177 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
|
|
||||||
import formElementIcons from '@/components/ui/form-element-icons';
|
import formElementIcons from '@/components/ui/form-element-icons';
|
||||||
import CrossIcon from '@/components/icons/CrossIcon';
|
import CrossIcon from '@/components/icons/CrossIcon';
|
||||||
import ChooserElement from '@/components/content-forms/ChooserElement';
|
import ChooserElement from '@/components/content-forms/ChooserElement';
|
||||||
import {DEFAULT_FEATURE_SET} from '@/consts/features.consts';
|
import { DEFAULT_FEATURE_SET } from '@/consts/features.consts';
|
||||||
|
|
||||||
|
export default {
|
||||||
export default {
|
props: {
|
||||||
props: {
|
element: {},
|
||||||
element: {},
|
index: {},
|
||||||
index: {},
|
hideAssignment: {
|
||||||
hideAssignment: {
|
type: Boolean,
|
||||||
type: Boolean,
|
default: false,
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
includeListOption: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
includeListOption: {
|
||||||
inject: ['features'],
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
components: {
|
|
||||||
ChooserElement,
|
|
||||||
CrossIcon,
|
|
||||||
Checkbox,
|
|
||||||
...formElementIcons,
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
inject: ['features'],
|
||||||
const hasDefaultFeatures = this.features === DEFAULT_FEATURE_SET;
|
|
||||||
return {
|
|
||||||
convertToList: false,
|
|
||||||
chooserTypes: [
|
|
||||||
{
|
|
||||||
type: 'subtitle',
|
|
||||||
block: 'subtitle',
|
|
||||||
title: 'Untertitel',
|
|
||||||
icon: 'title-icon',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'link',
|
|
||||||
block: 'link_block',
|
|
||||||
title: 'Link',
|
|
||||||
icon: 'link-icon',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'video',
|
|
||||||
block: 'video_block',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'image',
|
|
||||||
block: 'image_url_block',
|
|
||||||
title: 'Bild',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
block: 'text_block',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'assignment',
|
|
||||||
block: 'assignment',
|
|
||||||
icon: 'speech-bubble-icon',
|
|
||||||
title: 'Aufgabe & Ergebnis',
|
|
||||||
show: !this.hideAssignment && hasDefaultFeatures
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'document',
|
|
||||||
block: 'document_block',
|
|
||||||
title: 'Dokument',
|
|
||||||
show: hasDefaultFeatures
|
|
||||||
},
|
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ChooserElement,
|
||||||
|
CrossIcon,
|
||||||
|
Checkbox,
|
||||||
|
...formElementIcons,
|
||||||
|
},
|
||||||
|
|
||||||
],
|
data() {
|
||||||
};
|
const hasDefaultFeatures = this.features === DEFAULT_FEATURE_SET;
|
||||||
|
return {
|
||||||
|
convertToList: false,
|
||||||
|
chooserTypes: [
|
||||||
|
{
|
||||||
|
type: 'subtitle',
|
||||||
|
block: 'subtitle',
|
||||||
|
title: 'Untertitel',
|
||||||
|
icon: 'title-icon',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
block: 'link_block',
|
||||||
|
title: 'Link',
|
||||||
|
icon: 'link-icon',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'video',
|
||||||
|
block: 'video_block',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'image',
|
||||||
|
block: 'image_url_block',
|
||||||
|
title: 'Bild',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
block: 'text_block',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'assignment',
|
||||||
|
block: 'assignment',
|
||||||
|
icon: 'speech-bubble-icon',
|
||||||
|
title: 'Aufgabe & Ergebnis',
|
||||||
|
show: !this.hideAssignment && hasDefaultFeatures,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'document',
|
||||||
|
block: 'document_block',
|
||||||
|
title: 'Dokument',
|
||||||
|
show: hasDefaultFeatures,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
filteredChooserTypes() {
|
||||||
|
return this.chooserTypes.filter((type) => !('show' in type) || type.show); // display element if `show` is not set or if `show` evaluates to true
|
||||||
},
|
},
|
||||||
|
hasDefaultFeatures() {
|
||||||
computed: {
|
return this.features === DEFAULT_FEATURE_SET;
|
||||||
filteredChooserTypes() {
|
|
||||||
return this.chooserTypes.filter(type => !("show" in type) || type.show ); // display element if `show` is not set or if `show` evaluates to true
|
|
||||||
},
|
|
||||||
hasDefaultFeatures() {
|
|
||||||
return this.features === DEFAULT_FEATURE_SET;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
changeType(type) {
|
changeType(type) {
|
||||||
this.$emit('change-type', {
|
this.$emit('change-type', {
|
||||||
type,
|
type,
|
||||||
convertToList: this.convertToList,
|
convertToList: this.convertToList,
|
||||||
});
|
});
|
||||||
},
|
|
||||||
remove() {
|
|
||||||
this.$emit('remove');
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
remove() {
|
||||||
|
this.$emit('remove');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.content-block-element-chooser-widget {
|
|
||||||
display: -ms-grid;
|
|
||||||
|
|
||||||
@supports (display: grid) {
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
grid-template-columns: repeat(7, 1fr);
|
|
||||||
-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
|
||||||
grid-column-gap: 0;
|
|
||||||
font-family: $sans-serif-font-family;
|
|
||||||
text-align: center;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
// grid position in wrapper element
|
|
||||||
grid-column: 1 / -1;
|
|
||||||
|
|
||||||
/*IE10+*/
|
|
||||||
& > :nth-child(1) {
|
|
||||||
-ms-grid-column: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :nth-child(2) {
|
|
||||||
-ms-grid-column: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :nth-child(3) {
|
|
||||||
-ms-grid-column: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :nth-child(4) {
|
|
||||||
-ms-grid-column: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :nth-child(5) {
|
|
||||||
-ms-grid-column: 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :nth-child(6) {
|
|
||||||
-ms-grid-column: 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--no-assignment {
|
|
||||||
grid-template-columns: repeat(5, 1fr);
|
|
||||||
-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__wrapper {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 180px 1fr 50px;
|
|
||||||
align-items: center;
|
|
||||||
row-gap: $small-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__remove-button {
|
|
||||||
grid-column: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__heading {
|
|
||||||
@include heading-3;
|
|
||||||
margin-bottom: 0;
|
|
||||||
grid-column: 1;
|
|
||||||
grid-row: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__list-toggle {
|
|
||||||
margin-bottom: 0;
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.content-block-element-chooser-widget {
|
||||||
|
display: -ms-grid;
|
||||||
|
|
||||||
|
@supports (display: grid) {
|
||||||
|
display: grid;
|
||||||
}
|
}
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
grid-column-gap: 0;
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
// grid position in wrapper element
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
|
||||||
|
/*IE10+*/
|
||||||
|
& > :nth-child(1) {
|
||||||
|
-ms-grid-column: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :nth-child(2) {
|
||||||
|
-ms-grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :nth-child(3) {
|
||||||
|
-ms-grid-column: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :nth-child(4) {
|
||||||
|
-ms-grid-column: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :nth-child(5) {
|
||||||
|
-ms-grid-column: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :nth-child(6) {
|
||||||
|
-ms-grid-column: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--no-assignment {
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 180px 1fr 50px;
|
||||||
|
align-items: center;
|
||||||
|
row-gap: $small-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__remove-button {
|
||||||
|
grid-column: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
@include heading-3;
|
||||||
|
margin-bottom: 0;
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__list-toggle {
|
||||||
|
margin-bottom: 0;
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,132 +1,119 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="document-form" ref="documentform">
|
||||||
class="document-form"
|
<div v-if="!value.url" ref="uploadcare-panel" />
|
||||||
ref="documentform"
|
<div class="document-form__spinner" v-if="loading">
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="!value.url"
|
|
||||||
ref="uploadcare-panel"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="document-form__spinner"
|
|
||||||
v-if="loading"
|
|
||||||
>
|
|
||||||
<loading-icon class="document-form__loading-icon" />
|
<loading-icon class="document-form__loading-icon" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="document-form__uploaded" v-if="value.url">
|
||||||
class="document-form__uploaded"
|
|
||||||
v-if="value.url"
|
|
||||||
>
|
|
||||||
<document-icon class="document-form__icon" />
|
<document-icon class="document-form__icon" />
|
||||||
<a
|
<a :href="previewUrl" class="document-form__link" target="_blank">{{ previewLink }}</a>
|
||||||
:href="previewUrl"
|
|
||||||
class="document-form__link"
|
|
||||||
target="_blank"
|
|
||||||
>{{ previewLink }}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {uploadcare} from '@/helpers/uploadcare';
|
import { uploadcare } from '@/helpers/uploadcare';
|
||||||
import LoadingIcon from '@/components/icons/LoadingIcon';
|
import LoadingIcon from '@/components/icons/LoadingIcon';
|
||||||
|
|
||||||
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
|
const DocumentIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/DocumentIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'index'],
|
props: ['value', 'index'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
LoadingIcon,
|
LoadingIcon,
|
||||||
DocumentIcon,
|
DocumentIcon,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
previewUrl() {
|
||||||
|
if (this.value && this.value.url) {
|
||||||
|
return this.value.url;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
|
previewLink() {
|
||||||
data() {
|
if (this.value && this.value.url) {
|
||||||
return {
|
const parts = this.value.url.split('/');
|
||||||
loading: false,
|
return parts[parts.length - 1];
|
||||||
};
|
}
|
||||||
|
return '';
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
mounted() {
|
||||||
previewUrl() {
|
uploadcare(
|
||||||
if (this.value && this.value.url) {
|
this,
|
||||||
return this.value.url;
|
(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 => {
|
|
||||||
this.$emit('change-url', url, this.index);
|
this.$emit('change-url', url, this.index);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}, () => {
|
},
|
||||||
|
() => {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
}
|
||||||
});
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.document-form {
|
.document-form {
|
||||||
&__uploaded {
|
&__uploaded {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__link {
|
&__link {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__spinner {
|
&__spinner {
|
||||||
width: 100%;
|
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;
|
height: 150px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
align-items: center;
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
&__loading-icon {
|
font-weight: $font-weight-regular;
|
||||||
@include spin;
|
text-decoration: underline;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,149 +1,134 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="image-form">
|
<div class="image-form">
|
||||||
<div
|
<div class="image-form__error" v-if="hadError">
|
||||||
class="image-form__error"
|
Ups, das scheint kein Bild zu sein. Bitte versuche es nochmal mit einer anderen Datei, oder lade die Datei als
|
||||||
v-if="hadError"
|
<a class="image-form__link" @click="switchToDocument">Dokument</a> hoch.
|
||||||
>
|
|
||||||
Ups, das scheint kein Bild zu sein. Bitte versuche es nochmal mit einer anderen Datei, oder lade die Datei als <a
|
|
||||||
class="image-form__link"
|
|
||||||
@click="switchToDocument"
|
|
||||||
>Dokument</a> hoch.
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="image-form__spinner" v-if="loading">
|
||||||
class="image-form__spinner"
|
|
||||||
v-if="loading"
|
|
||||||
>
|
|
||||||
<loading-icon class="image-form__loading-icon" />
|
<loading-icon class="image-form__loading-icon" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="!value.url || hadError" ref="uploadcare-panel" />
|
||||||
v-if="!value.url || hadError"
|
|
||||||
ref="uploadcare-panel"
|
|
||||||
/>
|
|
||||||
<div v-if="value.url && !hadError">
|
<div v-if="value.url && !hadError">
|
||||||
<img
|
<img alt="" :src="previewUrl" @error="error" />
|
||||||
alt=""
|
|
||||||
:src="previewUrl"
|
|
||||||
@error="error"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import uploadcare from 'uploadcare-widget';
|
import uploadcare from 'uploadcare-widget';
|
||||||
import LoadingIcon from '@/components/icons/LoadingIcon';
|
import LoadingIcon from '@/components/icons/LoadingIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'index'],
|
props: ['value', 'index'],
|
||||||
components: {LoadingIcon},
|
components: { LoadingIcon },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hadError: false,
|
hadError: false,
|
||||||
uploadcarePanel: null,
|
uploadcarePanel: null,
|
||||||
url: '',
|
url: '',
|
||||||
filename: '',
|
filename: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
previewUrl: function () {
|
||||||
|
if (this.value && this.value.url) {
|
||||||
|
return this.value.url + '-/preview/200x200/';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
computed: {
|
},
|
||||||
previewUrl: function () {
|
mounted() {
|
||||||
if (this.value && this.value.url) {
|
this.mountUploadcare();
|
||||||
return this.value.url + '-/preview/200x200/';
|
},
|
||||||
}
|
methods: {
|
||||||
return null;
|
error() {
|
||||||
},
|
this.hadError = true;
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.mountUploadcare();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
error() {
|
|
||||||
this.hadError = true;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.mountUploadcare();
|
this.mountUploadcare();
|
||||||
}, 0);
|
}, 0);
|
||||||
},
|
},
|
||||||
mountUploadcare() {
|
mountUploadcare() {
|
||||||
this.uploadcarePanel = uploadcare.openPanel(this.$refs['uploadcare-panel'], null, {
|
this.uploadcarePanel = uploadcare.openPanel(this.$refs['uploadcare-panel'], null, {
|
||||||
tabs: ['file'],
|
tabs: ['file'],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.uploadcarePanel.done((panelResult) => {
|
||||||
|
this.loading = true;
|
||||||
|
panelResult.done((fileInfo) => {
|
||||||
|
this.hadError = false;
|
||||||
|
this.loading = false;
|
||||||
|
this.url = fileInfo.cdnUrl;
|
||||||
|
this.filename = fileInfo.name;
|
||||||
|
this.$emit('change-url', fileInfo.cdnUrl, this.index);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.uploadcarePanel.done(panelResult => {
|
// the api also provides these methods
|
||||||
this.loading = true;
|
// panelResult.progress(p => {});
|
||||||
panelResult.done(fileInfo => {
|
// panelResult.fail(uploadResult => {});
|
||||||
this.hadError = false;
|
});
|
||||||
this.loading = false;
|
|
||||||
this.url = fileInfo.cdnUrl;
|
|
||||||
this.filename = fileInfo.name;
|
|
||||||
this.$emit('change-url', fileInfo.cdnUrl, this.index);
|
|
||||||
});
|
|
||||||
|
|
||||||
// the api also provides these methods
|
|
||||||
// panelResult.progress(p => {});
|
|
||||||
// panelResult.fail(uploadResult => {});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
switchToDocument() {
|
|
||||||
this.$emit('switch-to-document', this.index, {
|
|
||||||
url: `${this.url}${this.filename}`,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
switchToDocument() {
|
||||||
|
this.$emit('switch-to-document', this.index, {
|
||||||
|
url: `${this.url}${this.filename}`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.image-form {
|
.image-form {
|
||||||
&__error {
|
&__error {
|
||||||
@include regular-text;
|
@include regular-text;
|
||||||
margin-bottom: $medium-spacing;
|
margin-bottom: $medium-spacing;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__spinner {
|
&__spinner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__loading-icon {
|
||||||
|
@include spin;
|
||||||
|
fill: $color-silver-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
text-decoration: underline;
|
||||||
|
@include regular-text;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__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;
|
height: 150px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
align-items: center;
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
&__loading-icon {
|
font-weight: $font-weight-regular;
|
||||||
@include spin;
|
|
||||||
fill: $color-silver-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@include regular-text;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,34 +5,34 @@
|
||||||
placeholder="Name erfassen..."
|
placeholder="Name erfassen..."
|
||||||
class="link-form__text skillbox-input"
|
class="link-form__text skillbox-input"
|
||||||
@input="$emit('change-text', $event.target.value, index)"
|
@input="$emit('change-text', $event.target.value, index)"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
:value="value.url"
|
:value="value.url"
|
||||||
placeholder="URL einfügen..."
|
placeholder="URL einfügen..."
|
||||||
class="link-form__url skillbox-input"
|
class="link-form__url skillbox-input"
|
||||||
@input="$emit('change-url', $event.target.value, index)"
|
@input="$emit('change-url', $event.target.value, index)"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'index']
|
props: ['value', 'index'],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.link-form {
|
.link-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-rows: auto;
|
grid-auto-rows: auto;
|
||||||
grid-row-gap: 11px;
|
grid-row-gap: 11px;
|
||||||
|
|
||||||
&__text,
|
&__text,
|
||||||
&__url {
|
&__url {
|
||||||
width: $modal-input-width;
|
width: $modal-input-width;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -12,38 +12,38 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import InputWithLabel from '@/components/ui/InputWithLabel';
|
import InputWithLabel from '@/components/ui/InputWithLabel';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
validator(value) {
|
validator(value) {
|
||||||
return Object.prototype.hasOwnProperty.call(value, 'text');
|
return Object.prototype.hasOwnProperty.call(value, 'text');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
index: {
|
|
||||||
type: Number,
|
|
||||||
default: -1
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
components: {InputWithLabel},
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: { InputWithLabel },
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
text() {
|
text() {
|
||||||
return this.value.text;
|
return this.value.text;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.subtitle-form {
|
.subtitle-form {
|
||||||
&__input {
|
&__input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -11,35 +11,35 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
validator(value) {
|
validator(value) {
|
||||||
return Object.prototype.hasOwnProperty.call(value, 'text');
|
return Object.prototype.hasOwnProperty.call(value, 'text');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
index: {
|
},
|
||||||
type: Number,
|
index: {
|
||||||
default: -1
|
type: Number,
|
||||||
}
|
default: -1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
text() {
|
text() {
|
||||||
return this.value.text ? this.value.text.replace(/<br(\/)?>/, '\n').replace(/(<([^>]+)>)/ig, '') : '';
|
return this.value.text ? this.value.text.replace(/<br(\/)?>/, '\n').replace(/(<([^>]+)>)/gi, '') : '';
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "~styles/helpers";
|
@import '~styles/helpers';
|
||||||
|
|
||||||
.text-form {
|
.text-form {
|
||||||
&__input {
|
&__input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -4,53 +4,50 @@
|
||||||
<span class="text-form-with-help-text__title">{{ title }}</span>
|
<span class="text-form-with-help-text__title">{{ title }}</span>
|
||||||
<helpful-tooltip :text="helpText" />
|
<helpful-tooltip :text="helpText" />
|
||||||
</h3>
|
</h3>
|
||||||
<text-form
|
<text-form :value="v" @change-text="$emit('change', $event)" />
|
||||||
:value="v"
|
|
||||||
@change-text="$emit('change', $event)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TextForm from '@/components/content-forms/TextForm';
|
import TextForm from '@/components/content-forms/TextForm';
|
||||||
import HelpfulTooltip from '@/components/HelpfulTooltip';
|
import HelpfulTooltip from '@/components/HelpfulTooltip';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['title', 'value', 'helpText'],
|
props: ['title', 'value', 'helpText'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
TextForm,
|
TextForm,
|
||||||
HelpfulTooltip
|
HelpfulTooltip,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
v() {
|
||||||
|
return {
|
||||||
|
text: this.value,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
},
|
||||||
computed: {
|
};
|
||||||
v() {
|
|
||||||
return {
|
|
||||||
text: this.value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_functions.scss";
|
@import '@/styles/_functions.scss';
|
||||||
|
|
||||||
.text-form-with-help-text {
|
.text-form-with-help-text {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
|
|
||||||
&__heading {
|
&__heading {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
font-size: toRem(22px);
|
|
||||||
font-weight: 600;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: toRem(22px);
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,146 +1,130 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="tip-tap">
|
<div class="tip-tap">
|
||||||
<editor-content
|
<editor-content class="tip-tap__editor-wrapper" :editor="editor" />
|
||||||
class="tip-tap__editor-wrapper"
|
|
||||||
:editor="editor"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<toggle
|
<toggle :bordered="false" :checked="isList" label="Als Liste formatieren" @input="toggleList" />
|
||||||
:bordered="false"
|
|
||||||
:checked="isList"
|
|
||||||
label="Als Liste formatieren"
|
|
||||||
@input="toggleList"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue, {PropType} from 'vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import {Editor, EditorContent} from "@tiptap/vue-2";
|
import { Editor, EditorContent } from '@tiptap/vue-2';
|
||||||
import Document from '@tiptap/extension-document';
|
import Document from '@tiptap/extension-document';
|
||||||
import Paragraph from '@tiptap/extension-paragraph';
|
import Paragraph from '@tiptap/extension-paragraph';
|
||||||
import Text from '@tiptap/extension-text';
|
import Text from '@tiptap/extension-text';
|
||||||
import BulletList from '@tiptap/extension-bullet-list';
|
import BulletList from '@tiptap/extension-bullet-list';
|
||||||
import ListItem from '@tiptap/extension-list-item';
|
import ListItem from '@tiptap/extension-list-item';
|
||||||
import Toggle from "@/components/ui/Toggle.vue";
|
import Toggle from '@/components/ui/Toggle.vue';
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
editor: Editor | undefined;
|
editor: Editor | undefined;
|
||||||
}
|
}
|
||||||
interface Value {
|
interface Value {
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Object as PropType<Value>,
|
type: Object as PropType<Value>,
|
||||||
validator(value: Value) {
|
validator(value: Value) {
|
||||||
return Object.prototype.hasOwnProperty.call(value, 'text');
|
return Object.prototype.hasOwnProperty.call(value, 'text');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Toggle,
|
||||||
|
EditorContent,
|
||||||
|
},
|
||||||
|
|
||||||
|
data(): Data {
|
||||||
|
return {
|
||||||
|
editor: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isList(): boolean {
|
||||||
|
return this.editor?.isActive('bulletList') || false;
|
||||||
|
},
|
||||||
|
text(): string {
|
||||||
|
return this.value.text;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
value({ text }: Value) {
|
||||||
|
const editor = this.editor as Editor; // editor is always initialized on mount, cast it
|
||||||
|
const isSame = editor.getHTML() === text;
|
||||||
|
|
||||||
|
if (isSame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.commands.setContent(text, false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
editorProps: {
|
||||||
|
attributes: {
|
||||||
|
class: 'tip-tap__editor',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
content: this.text,
|
||||||
|
extensions: [Document, Paragraph, Text, BulletList, ListItem],
|
||||||
components: {
|
onUpdate: () => {
|
||||||
Toggle,
|
const text = (this.editor as Editor).getHTML();
|
||||||
EditorContent
|
this.$emit('input', text);
|
||||||
},
|
this.$emit('change-text', text);
|
||||||
|
|
||||||
data(): Data {
|
|
||||||
return {
|
|
||||||
editor: undefined,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
isList(): boolean {
|
|
||||||
return this.editor?.isActive('bulletList') || false;
|
|
||||||
},
|
},
|
||||||
text(): string {
|
});
|
||||||
return this.value.text;
|
},
|
||||||
}
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.editor?.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleList() {
|
||||||
|
const editor = this.editor as Editor;
|
||||||
|
editor.chain().selectAll().toggleBulletList().run();
|
||||||
},
|
},
|
||||||
|
},
|
||||||
watch: {
|
});
|
||||||
value({text}: Value) {
|
|
||||||
const editor = this.editor as Editor; // editor is always initialized on mount, cast it
|
|
||||||
const isSame = editor.getHTML() === text;
|
|
||||||
|
|
||||||
if (isSame) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.commands.setContent(text, false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.editor = new Editor({
|
|
||||||
editorProps: {
|
|
||||||
attributes: {
|
|
||||||
class: 'tip-tap__editor'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content: this.text,
|
|
||||||
extensions: [
|
|
||||||
Document,
|
|
||||||
Paragraph,
|
|
||||||
Text,
|
|
||||||
BulletList,
|
|
||||||
ListItem
|
|
||||||
],
|
|
||||||
onUpdate: () => {
|
|
||||||
const text=(this.editor as Editor).getHTML();
|
|
||||||
this.$emit('input', text);
|
|
||||||
this.$emit('change-text', text);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy() {
|
|
||||||
this.editor?.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
toggleList() {
|
|
||||||
const editor = this.editor as Editor;
|
|
||||||
editor.chain().selectAll().toggleBulletList().run();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~styles/helpers';
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
.tip-tap {
|
||||||
.tip-tap {
|
&__editor-wrapper {
|
||||||
|
margin-bottom: $medium-spacing;
|
||||||
&__editor-wrapper {
|
|
||||||
margin-bottom: $medium-spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.tip-tap__editor) {
|
|
||||||
@include inputstyle;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(ul) {
|
|
||||||
padding-left: $medium-spacing;
|
|
||||||
list-style: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(li) {
|
|
||||||
@include inputfont;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(div) {
|
|
||||||
@include inputfont;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(p) {
|
|
||||||
@include inputfont;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.tip-tap__editor) {
|
||||||
|
@include inputstyle;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(ul) {
|
||||||
|
padding-left: $medium-spacing;
|
||||||
|
list-style: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(li) {
|
||||||
|
@include inputfont;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(div) {
|
||||||
|
@include inputfont;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(p) {
|
||||||
|
@include inputfont;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div class="video-form" v-if="!isVimeo && !isYoutube && !isSrf">
|
||||||
class="video-form"
|
|
||||||
v-if="!isVimeo && !isYoutube && !isSrf"
|
|
||||||
>
|
|
||||||
<info-icon class="video-form__help-icon help-text__icon" />
|
<info-icon class="video-form__help-icon help-text__icon" />
|
||||||
<p class="video-form__help-description help-text__description">
|
<p class="video-form__help-description help-text__description">
|
||||||
Sie können Videos auf <a
|
Sie können Videos auf
|
||||||
class="video-form__platform-link help-text__link"
|
<a class="video-form__platform-link help-text__link" href="https://youtube.com/" target="_blank">Youtube</a>
|
||||||
href="https://youtube.com/"
|
oder <a class="video-form__platform-link help-text__link" href="https://vimeo.com/" target="_blank">Vimeo</a>
|
||||||
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.
|
hochladen und anschliessen einen Link hier einfügen.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -24,7 +14,7 @@
|
||||||
class="video-form__video-link skillbox-input"
|
class="video-form__video-link skillbox-input"
|
||||||
placeholder="Bsp: https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
placeholder="Bsp: https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||||
@input="$emit('change-url', $event.target.value, index)"
|
@input="$emit('change-url', $event.target.value, index)"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isYoutube">
|
<div v-if="isYoutube">
|
||||||
|
|
@ -40,66 +30,64 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
||||||
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
||||||
import SrfEmbed from '@/components/videos/SrfEmbed';
|
import SrfEmbed from '@/components/videos/SrfEmbed';
|
||||||
import {isVimeoUrl, isYoutubeUrl, isSrfUrl} from '@/helpers/video';
|
import { isVimeoUrl, isYoutubeUrl, isSrfUrl } from '@/helpers/video';
|
||||||
const InfoIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon');
|
const InfoIcon = () => import(/* webpackChunkName: "icons" */ '@/components/icons/InfoIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'index'],
|
props: ['value', 'index'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
InfoIcon,
|
InfoIcon,
|
||||||
YoutubeEmbed,
|
YoutubeEmbed,
|
||||||
VimeoEmbed,
|
VimeoEmbed,
|
||||||
SrfEmbed
|
SrfEmbed,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isYoutube() {
|
||||||
|
return isYoutubeUrl(this.value.url);
|
||||||
},
|
},
|
||||||
|
isVimeo() {
|
||||||
computed: {
|
return isVimeoUrl(this.value.url);
|
||||||
isYoutube() {
|
},
|
||||||
return isYoutubeUrl(this.value.url);
|
isSrf() {
|
||||||
},
|
return isSrfUrl(this.value.url);
|
||||||
isVimeo() {
|
},
|
||||||
return isVimeoUrl(this.value.url);
|
},
|
||||||
},
|
};
|
||||||
isSrf() {
|
|
||||||
return isSrfUrl(this.value.url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import '@/styles/_variables.scss';
|
||||||
@import "@/styles/_functions.scss";
|
@import '@/styles/_functions.scss';
|
||||||
|
|
||||||
.video-form {
|
.video-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-rows: auto;
|
grid-auto-rows: auto;
|
||||||
grid-template-columns: 40px 1fr;
|
grid-template-columns: 40px 1fr;
|
||||||
grid-column-gap: 16px;
|
grid-column-gap: 16px;
|
||||||
grid-row-gap: 20px;
|
grid-row-gap: 20px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__help-icon {
|
&__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-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>
|
</style>
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue