Todas las cosas
This commit is contained in:
commit
07d23b5971
413 changed files with 42587 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules/
|
1
0.0c5b2e6a.chunk.js.map
Normal file
1
0.0c5b2e6a.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
1
6.776c1e8b.chunk.js.map
Normal file
1
6.776c1e8b.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
1
7.c65299ef.chunk.css.map
Normal file
1
7.c65299ef.chunk.css.map
Normal file
File diff suppressed because one or more lines are too long
1
7.f024fa6c.chunk.js.map
Normal file
1
7.f024fa6c.chunk.js.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"sources":[],"names":[],"mappings":"","file":"static/js/7.f024fa6c.chunk.js","sourceRoot":""}
|
1
8.16508763.chunk.js.map
Normal file
1
8.16508763.chunk.js.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"sources":[],"names":[],"mappings":"","file":"static/js/8.16508763.chunk.js","sourceRoot":""}
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# [Arreglando bugs ajenos](https://nulo.in/Arreglando%20bugs%20ajenos.html)
|
||||||
|
|
||||||
|
Pista: el código está en <sources-gen/>. Añadí la config de nginx de learngerman.nulo.in en <learngerman.nulo.in.conf>.
|
47
learngerman.nulo.in.conf
Normal file
47
learngerman.nulo.in.conf
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
server {
|
||||||
|
ssl_certificate /etc/letsencrypt/live/learngerman.nulo.in/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/learngerman.nulo.in/privkey.pem;
|
||||||
|
ssl_trusted_certificate /etc/letsencrypt/live/learngerman.nulo.in/chain.pem;
|
||||||
|
|
||||||
|
include snippets/https.conf;
|
||||||
|
server_name learngerman.nulo.in;
|
||||||
|
root /var/www/learngerman.nulo.in/;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
index index.html;
|
||||||
|
try_files $uri /index.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^(\/graphql|\/auth\/login|\/profiles) {
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||||
|
#
|
||||||
|
# Custom headers and headers various browsers *should* be OK with but aren't
|
||||||
|
#
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
||||||
|
#
|
||||||
|
# Tell client that this pre-flight info is valid for 20 days
|
||||||
|
#
|
||||||
|
add_header 'Access-Control-Max-Age' 1728000;
|
||||||
|
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
||||||
|
add_header 'Content-Length' 0;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
if ($request_method = 'POST') {
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
|
||||||
|
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
||||||
|
}
|
||||||
|
if ($request_method = 'GET') {
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
|
||||||
|
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
||||||
|
}
|
||||||
|
proxy_pass https://learngerman.dw.com;
|
||||||
|
}
|
||||||
|
|
||||||
|
include snippets/acme.conf;
|
||||||
|
}
|
4
links
Normal file
4
links
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
https://learngerman.dw.com/static/css/main.f50335e4.chunk.css.map
|
||||||
|
https://learngerman.dw.com/static/css/7.c65299ef.chunk.css.map
|
||||||
|
https://learngerman.dw.com/static/css/playerPlugins-video.4cb21404.chunk.css.map
|
||||||
|
https://learngerman.dw.com/static/css/playerPlugins-audio.dcc31119.chunk.css.map
|
1
main.6c5fc115.chunk.js.map
Normal file
1
main.6c5fc115.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
1
main.f50335e4.chunk.css.map
Normal file
1
main.f50335e4.chunk.css.map
Normal file
File diff suppressed because one or more lines are too long
38
package.json
Normal file
38
package.json
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@apollo/client": "^3.4.16",
|
||||||
|
"classnames": "^2.3.1",
|
||||||
|
"crypto-hash": "^1.3.0",
|
||||||
|
"graphql": "^15.6.1",
|
||||||
|
"graphql-tag": "^2.12.5",
|
||||||
|
"minimist": "^1.2.5",
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-beforeunload": "^2.5.2",
|
||||||
|
"react-dom": "^17.0.2",
|
||||||
|
"react-google-recaptcha": "^2.1.0",
|
||||||
|
"react-helmet-async": "^1.1.2",
|
||||||
|
"react-hook-form": "^7.17.2",
|
||||||
|
"react-redux": "^7.2.5",
|
||||||
|
"react-router": "^5.2.1",
|
||||||
|
"react-router-dom": "^5.3.0",
|
||||||
|
"react-simple-keyboard": "^3.2.104",
|
||||||
|
"redux": "^4.1.1",
|
||||||
|
"redux-storage": "https://github.com/react-stack/redux-storage",
|
||||||
|
"redux-storage-engine-localstorage": "^1.1.4",
|
||||||
|
"redux-thunk": "^2.3.0",
|
||||||
|
"simple-keyboard-layouts": "^3.0.197",
|
||||||
|
"source-map": "^0.7.3",
|
||||||
|
"styled-components": "^5.3.1",
|
||||||
|
"stylis": "^4.0.10",
|
||||||
|
"stylis-plugin-rtl": "^2.1.0",
|
||||||
|
"video.js": "^7.15.4",
|
||||||
|
"videojs-contrib-quality-levels": "^2.1.0",
|
||||||
|
"videojs-hls-quality-selector": "^1.1.4",
|
||||||
|
"videojs-seek-buttons": "^2.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-react": "^1.0.2",
|
||||||
|
"vite": "^2.6.5"
|
||||||
|
}
|
||||||
|
}
|
1
player-custom.19eb3d6e.chunk.js.map
Normal file
1
player-custom.19eb3d6e.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
1
playerPlugins-audio.4aa8d1ef.chunk.js.map
Normal file
1
playerPlugins-audio.4aa8d1ef.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
1
playerPlugins-audio.dcc31119.chunk.css.map
Normal file
1
playerPlugins-audio.dcc31119.chunk.css.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"sources":["webpack://node_modules/videojs-seek-buttons/dist/videojs-seek-buttons.css"],"names":[],"mappings":"AAAA,mEAAmE,CACnE,2BAA2B,qBAAqB,CAAC,cAAc,CAAC,eAAe,CAAC,iBAAiB,CAAC,8LAAiM,wBAAwB,CAAC,4BAA4B,CAAC,gCAAgC,CAAC,eAAe,CAAC,+CAAgD,wCAAwC,CAAC,4CAA4C,CAAC,gDAAgD,CAAC,eAAe,CAAC,kNAAsN,YAAY,CAAC,wJAA0J,mCAAoC,CAAC,uCAAwC,CAAC,2CAA4C,CAAC,eAAe","file":"playerPlugins-audio.dcc31119.chunk.css","sourcesContent":["/*! @name videojs-seek-buttons @version 2.0.1 @license Apache-2.0 */\n.video-js .vjs-seek-button{font-family:'VideoJS';cursor:pointer;font-weight:400;font-style:normal}.video-js .vjs-seek-button.skip-back::before,.video-js.vjs-v6 .vjs-seek-button.skip-back .vjs-icon-placeholder::before,.video-js.vjs-v7 .vjs-seek-button.skip-back .vjs-icon-placeholder::before{transform:rotate(-45deg);-ms-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);content:'\\f116'}.video-js .vjs-seek-button.skip-forward::before{transform:rotateY(180deg) rotate(-45deg);-ms-transform:rotateY(180deg) rotate(-45deg);-webkit-transform:rotateY(180deg) rotate(-45deg);content:'\\f116'}.video-js.vjs-v6 .vjs-seek-button.skip-back::before,.video-js.vjs-v6 .vjs-seek-button.skip-forward::before,.video-js.vjs-v7 .vjs-seek-button.skip-back::before,.video-js.vjs-v7 .vjs-seek-button.skip-forward::before{content:none}.video-js.vjs-v6 .vjs-seek-button.skip-forward .vjs-icon-placeholder::before,.video-js.vjs-v7 .vjs-seek-button.skip-forward .vjs-icon-placeholder::before{transform:scale(-1,1) rotate(-45deg);-ms-transform:scale(-1,1) rotate(-45deg);-webkit-transform:scale(-1,1) rotate(-45deg);content:'\\f116'}"]}
|
1
playerPlugins-video.4cb21404.chunk.css.map
Normal file
1
playerPlugins-video.4cb21404.chunk.css.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"sources":["webpack://node_modules/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css"],"names":[],"mappings":"AAMA,mCAAmC,aAAa","file":"playerPlugins-video.4cb21404.chunk.css","sourcesContent":["/**\n * videojs-hls-quality-selector\n * @version 1.1.4\n * @copyright 2020 Chris Boustead (chris@forgemotion.com)\n * @license MIT\n */\n.video-js.vjs-hls-quality-selector{display:block}\n"]}
|
1
playerPlugins-video.5f4c24a0.chunk.js.map
Normal file
1
playerPlugins-video.5f4c24a0.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
1689
pnpm-lock.yaml
Normal file
1689
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
47
source-from-sourcemaps.js
Normal file
47
source-from-sourcemaps.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
const util = require("util");
|
||||||
|
const writeFileP = util.promisify(fs.writeFile);
|
||||||
|
const readFileP = util.promisify(fs.readFile);
|
||||||
|
const mkdirp = require("mkdirp");
|
||||||
|
const path = require("path");
|
||||||
|
const { SourceMapConsumer } = require("source-map");
|
||||||
|
const minimist = require("minimist");
|
||||||
|
|
||||||
|
async function processSource(consumer, src) {
|
||||||
|
const fsSrc =
|
||||||
|
"sources-gen/" +
|
||||||
|
src
|
||||||
|
.replace(/webpack:\/\/\//, "")
|
||||||
|
.replace(/~\//, "node_modules/")
|
||||||
|
.replace(/\?.+$/, "");
|
||||||
|
const source = consumer.sourceContentFor(src, true);
|
||||||
|
if (!source) {
|
||||||
|
console.warn("Unable to source:", src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await mkdirp(path.dirname(fsSrc));
|
||||||
|
await writeFileP(fsSrc, source, "UTF-8");
|
||||||
|
console.log(`Wrote ${fsSrc}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processFile(pth) {
|
||||||
|
const data = await readFileP(pth, "UTF-8");
|
||||||
|
return await SourceMapConsumer.with(data, null, async (consumer) => {
|
||||||
|
const processors = consumer.sources.map((src) =>
|
||||||
|
processSource(consumer, src)
|
||||||
|
);
|
||||||
|
return await Promise.all(processors);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = minimist(process.argv.slice(2));
|
||||||
|
const processors = args._.map((pth) => processFile(pth));
|
||||||
|
return await Promise.all(processors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!module.parent) {
|
||||||
|
main().then(() => process.exit(0));
|
||||||
|
}
|
14
sources-gen/.pnpm-debug.log
Normal file
14
sources-gen/.pnpm-debug.log
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"0 debug pnpm:scope": {
|
||||||
|
"selected": 1
|
||||||
|
},
|
||||||
|
"1 error pnpm": {
|
||||||
|
"code": "ERR_PNPM_NO_SCRIPT",
|
||||||
|
"err": {
|
||||||
|
"name": "pnpm",
|
||||||
|
"message": "Missing script: vite",
|
||||||
|
"code": "ERR_PNPM_NO_SCRIPT",
|
||||||
|
"stack": "pnpm: Missing script: vite\n at Object.handler (/home/nulo/.npm/prefix/lib/node_modules/pnpm/dist/pnpm.cjs:129183:15)\n at async /home/nulo/.npm/prefix/lib/node_modules/pnpm/dist/pnpm.cjs:133329:20\n at async run (/home/nulo/.npm/prefix/lib/node_modules/pnpm/dist/pnpm.cjs:133304:34)\n at async runPnpm (/home/nulo/.npm/prefix/lib/node_modules/pnpm/dist/pnpm.cjs:133514:5)\n at async /home/nulo/.npm/prefix/lib/node_modules/pnpm/dist/pnpm.cjs:133506:7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9364
sources-gen/assets/css/basestyles.css
Normal file
9364
sources-gen/assets/css/basestyles.css
Normal file
File diff suppressed because it is too large
Load diff
304
sources-gen/assets/css/customBaku.css
Normal file
304
sources-gen/assets/css/customBaku.css
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
.override-rtl{
|
||||||
|
direction:rtl;
|
||||||
|
}
|
||||||
|
.monolingual-course{
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
.override-ltr{
|
||||||
|
direction:ltr;
|
||||||
|
}
|
||||||
|
span.ltr{
|
||||||
|
left:0 !important;
|
||||||
|
right:inherit !important;
|
||||||
|
}
|
||||||
|
.override-strong strong{
|
||||||
|
font-weight: 700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tt-suggestion{
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) and (max-width: 991px) {
|
||||||
|
.override-ltr .col-lg-1,
|
||||||
|
.override-ltr .col-lg-10,
|
||||||
|
.override-ltr .col-lg-11,
|
||||||
|
.override-ltr .col-lg-12,
|
||||||
|
.override-ltr .col-lg-2,
|
||||||
|
.override-ltr .col-lg-3,
|
||||||
|
.override-ltr .col-lg-4,
|
||||||
|
.override-ltr .col-lg-5,
|
||||||
|
.override-ltr .col-lg-6,
|
||||||
|
.override-ltr .col-lg-7,
|
||||||
|
.override-ltr .col-lg-8,
|
||||||
|
.override-ltr .col-lg-9 {
|
||||||
|
float: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.override-ltr .col-lg-offset-2 {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.override-ltr .col-sm-offset-1 {
|
||||||
|
margin-left: 8.33333333%;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.override-ltr .col-lg-1,
|
||||||
|
.override-ltr .col-lg-10,
|
||||||
|
.override-ltr .col-lg-11,
|
||||||
|
.override-ltr .col-lg-12,
|
||||||
|
.override-ltr .col-lg-2,
|
||||||
|
.override-ltr .col-lg-3,
|
||||||
|
.override-ltr .col-lg-4,
|
||||||
|
.override-ltr .col-lg-5,
|
||||||
|
.override-ltr .col-lg-6,
|
||||||
|
.override-ltr .col-lg-7,
|
||||||
|
.override-ltr .col-lg-8,
|
||||||
|
.override-ltr .col-lg-9 {
|
||||||
|
float: left!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.override-ltr .col-lg-offset-2 {
|
||||||
|
margin-right: 0!important;
|
||||||
|
margin-left: 16.66666667%!important;
|
||||||
|
}
|
||||||
|
.override-ltr .col-sm-offset-1 {
|
||||||
|
margin-left: 8.33333333%;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.override-ltr div.row.vocabulary div.col-sm-3 p {
|
||||||
|
margin-right: 30px!important;
|
||||||
|
margin-left: auto!important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.override-ltr a.audio-link:before {
|
||||||
|
background-position: left top;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.consonants:hover {
|
||||||
|
border-bottom: 2px solid #23527c!important;
|
||||||
|
}
|
||||||
|
.consonants {
|
||||||
|
border-bottom: 1px solid #23527c!important;
|
||||||
|
color: #23527c!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container.page-container {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#header-row div.row-menu div.lecture-nav-container div.navbar nav.lecture-nav .navbar-toggle:focus .icon-close-cross {
|
||||||
|
background: url(../svg/nav-cross-black-lg.svg) no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
header div.row-menu div.navbar.navbar-default.navbar-static-top nav.main-nav .navbar-toggle:focus .close-cross {
|
||||||
|
background: url(../svg/nav-cross-xs.svg) no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#the-basics.rtl span.twitter-typeahead {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
div#the-basics.rtl span.twitter-typeahead .input-lg{
|
||||||
|
padding-left: 20px;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#the-basics.rtl span.twitter-typeahead input[type="search"].tt-input {
|
||||||
|
background-image: url(../svg/icon-lupe.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 44px;
|
||||||
|
direction: rtl;
|
||||||
|
|
||||||
|
background-position: 7% 14px;
|
||||||
|
}
|
||||||
|
span.course-score-ltr,
|
||||||
|
button.course-reset-ltr {
|
||||||
|
left: inherit !important;
|
||||||
|
right: 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-row {
|
||||||
|
margin-bottom: 58px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
div#the-basics.rtl span.twitter-typeahead input[type="search"].tt-input {
|
||||||
|
background-position: 3% 14px;
|
||||||
|
}
|
||||||
|
span.course-score-ltr,
|
||||||
|
button.course-reset-ltr {
|
||||||
|
left: inherit !important;
|
||||||
|
right: 56px !important;
|
||||||
|
}
|
||||||
|
#header-row {
|
||||||
|
margin-bottom: 58px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
div#the-basics.rtl span.twitter-typeahead input[type="search"].tt-input {
|
||||||
|
background-position: 2% 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.course-score-ltr,
|
||||||
|
button.course-reset-ltr {
|
||||||
|
left: inherit !important;
|
||||||
|
right: 20px !important;
|
||||||
|
}
|
||||||
|
#header-row {
|
||||||
|
margin-bottom: 84px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.richtext-content-container img {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#newsletter-subscribe, #newsletter-unsubscribe {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile-button {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.need-help-link {
|
||||||
|
padding-top:20px;
|
||||||
|
padding-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(59, 68, 77, 0.9);
|
||||||
|
z-index: 1000;
|
||||||
|
font: normal normal 400 12px/18px Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie--visible > div {
|
||||||
|
transition: 350ms 250ms ease-out;
|
||||||
|
transform: translateY(0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__wrap {
|
||||||
|
width: 940px;
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
margin: 18px auto;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -moz-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
-webkit-justify-content: space-between;
|
||||||
|
-moz-justify-content: space-between;
|
||||||
|
justify-content: space-between;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-moz-align-items: center;
|
||||||
|
align-items: center;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 940px) {
|
||||||
|
.cookie__wrap {
|
||||||
|
width: auto;
|
||||||
|
margin: 18px 18px;
|
||||||
|
flex-direction: column;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-moz-box-direction: normal;
|
||||||
|
-moz-box-orient: vertical;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__text {
|
||||||
|
-ms-align-self: flex-start;
|
||||||
|
-webkit-align-self: flex-start;
|
||||||
|
-moz-align-self: flex-start;
|
||||||
|
-ms-flex-item-align: start;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__buttons {
|
||||||
|
-ms-align-self: flex-end;
|
||||||
|
-webkit-align-self: flex-end;
|
||||||
|
-moz-align-self: flex-end;
|
||||||
|
-ms-flex-item-align: end;
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__item {
|
||||||
|
-ms-flex-item-align: stretch;
|
||||||
|
-webkit-align-self: stretch;
|
||||||
|
-moz-align-self: stretch;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__text {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__buttons {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -moz-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
-webkit-justify-content: space-between;
|
||||||
|
-moz-justify-content: space-between;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie__buttons a {
|
||||||
|
border: none;
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
padding: 7px 14px 8px;
|
||||||
|
font-weight: 700;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.cookie__btn--more {
|
||||||
|
background-color: rgb(127, 136, 145);
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.cookie__btn--more:hover {
|
||||||
|
background-color: rgb(216, 221, 226);
|
||||||
|
color: rgb(59, 68, 77);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.cookie__btn--ok {
|
||||||
|
background-color: rgb(0, 165, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.cookie__btn--ok:hover {
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
color: rgb(0, 165, 255);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a.glossar-modal.custom-modal:focus {
|
||||||
|
border: 2px solid #0098FF;
|
||||||
|
}
|
8148
sources-gen/assets/css/stylesheets.css
Normal file
8148
sources-gen/assets/css/stylesheets.css
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/dwtheantiquab-w5plain.94c5b804.woff";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/dwtheantiquab-w5plain.524a5eac.woff2";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/DWTheAntiquaB-W5PlainItalic.0c806fe1.woff";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/DWTheAntiquaB-W5PlainItalic.390937af.woff2";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/DWTheAntiquaB-W7Bold.73a35783.woff";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/DWTheAntiquaB-W7Bold.c739cf0d.woff2";
|
4
sources-gen/assets/icons/DwClaim.jsx
Normal file
4
sources-gen/assets/icons/DwClaim.jsx
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { ReactComponent as ClaimLogo } from '../svg/dw-claim.svg';
|
||||||
|
|
||||||
|
export const StyledClaimLogo = styled(props => <ClaimLogo {...props} />)``;
|
4
sources-gen/assets/icons/DwLogo.jsx
Normal file
4
sources-gen/assets/icons/DwLogo.jsx
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { ReactComponent as Logo } from '../svg/dw-logo.svg';
|
||||||
|
|
||||||
|
export const StyledLogo = styled(props => <Logo {...props} />)``;
|
6
sources-gen/assets/icons/Smiley.jsx
Normal file
6
sources-gen/assets/icons/Smiley.jsx
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { ReactComponent as SmileyPositive } from '../svg/smiley-positive.svg';
|
||||||
|
import { ReactComponent as SmileyNegative } from '../svg/smiley-negative.svg';
|
||||||
|
|
||||||
|
export const StyledSmileyPositive = styled(SmileyPositive)``;
|
||||||
|
export const StyledSmileyNegative = styled(SmileyNegative)``;
|
4
sources-gen/assets/icons/ToggleableArrowIcon.jsx
Normal file
4
sources-gen/assets/icons/ToggleableArrowIcon.jsx
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { ReactComponent as ToggleableArrowIcon } from '../svg/toggleableArrow.svg';
|
||||||
|
|
||||||
|
export const StyledToggleableArrowIcon = styled(props => <ToggleableArrowIcon {...props} />)``;
|
1
sources-gen/assets/images/bg-dw-desktop.jpg
Normal file
1
sources-gen/assets/images/bg-dw-desktop.jpg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/bg-dw-desktop.4aec073f.jpg";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/course_landing-1200x675.f68dc5b5.jpg";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/course_landing-480x270.5a82869e.jpg";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/course_landing-768x432.d54bc099.jpg";
|
|
@ -0,0 +1 @@
|
||||||
|
export default __webpack_public_path__ + "static/media/course_landing-992x558.4309e861.jpg";
|
36
sources-gen/assets/svg/dw-claim.svg.js
Normal file
36
sources-gen/assets/svg/dw-claim.svg.js
Normal file
File diff suppressed because one or more lines are too long
2
sources-gen/assets/svg/dw-logo-mobile.svg.js
Normal file
2
sources-gen/assets/svg/dw-logo-mobile.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/dw-logo-mobile.7e6e58ec.svg";
|
2
sources-gen/assets/svg/dw-logo-tablet.svg.js
Normal file
2
sources-gen/assets/svg/dw-logo-tablet.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/dw-logo-tablet.ac032dbb.svg";
|
37
sources-gen/assets/svg/dw-logo.svg.js
Normal file
37
sources-gen/assets/svg/dw-logo.svg.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
var _ref2 = /*#__PURE__*/React.createElement("g", {
|
||||||
|
className: "logoBox",
|
||||||
|
fillRule: "evenodd"
|
||||||
|
}, /*#__PURE__*/React.createElement("g", {
|
||||||
|
className: "logoLogo"
|
||||||
|
}, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M15.5929091,3.39736364 C22.287,3.39736364 27.714,8.82381818 27.714,15.5184545 C27.714,22.2125455 22.287,27.6392727 15.5929091,27.6392727 C8.89881818,27.6392727 3.47181818,22.2125455 3.47181818,15.5184545 C3.47181818,8.82381818 8.89881818,3.39736364 15.5929091,3.39736364 L15.5929091,3.39736364 Z M26.9959091,5.16463636 C29.8276364,1.99527273 33.9458182,0 38.5303636,0 C47.0694545,0 53.9920909,6.92236364 53.9920909,15.4617273 C53.9920909,24.0010909 47.0694545,30.9234545 38.5303636,30.9234545 C33.9458182,30.9234545 29.8276364,28.9281818 26.9959091,25.7585455 C24.1644545,28.9281818 20.046,30.9234545 15.4614545,30.9234545 C6.92209091,30.9234545 0,24.0010909 0,15.4617273 C0,6.92236364 6.92209091,1.93784382e-15 15.4614545,1.93784382e-15 C20.046,1.93784382e-15 24.1644545,1.99527273 26.9959091,5.16463636 L26.9959091,5.16463636 Z M15.9913636,13.0819091 L12.6553636,13.0819091 L12.6553636,18.0845455 L15.9913636,18.0845455 C18.4150909,18.0845455 19.2714545,17.0787273 19.2714545,15.5833636 C19.2714545,14.088 18.4085455,13.0819091 15.9913636,13.0819091 L15.9913636,13.0819091 Z M16.4511818,9.59536364 C19.8250909,9.59536364 23.2835455,11.292 23.2835455,15.5828182 C23.2835455,19.8739091 19.8250909,21.5705455 16.4511818,21.5705455 L8.886,21.5705455 L8.886,9.59536364 L16.4511818,9.59536364 L16.4511818,9.59536364 Z M35.4119983,15.9318147 L37.5403715,10.1204985 L40.4334297,10.1204985 L42.5618029,15.9318147 L44.2678615,10.1204985 L48.0692727,10.1204985 L44.4908946,21.3263197 L41.2676315,21.3263197 L38.9674938,15.9016908 L36.7070387,21.3263197 L33.483486,21.3263197 L29.9048182,10.1204985 L33.7062294,10.1204985 L35.4119983,15.9318147 L35.4119983,15.9318147 Z",
|
||||||
|
id: "Shape"
|
||||||
|
})));
|
||||||
|
|
||||||
|
function SvgDwLogo(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
viewBox: "0 0 54 31",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, _ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgDwLogo);
|
||||||
|
export default __webpack_public_path__ + "static/media/dw-logo.ff9012af.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
2
sources-gen/assets/svg/icon-course-cert-gray.svg.js
Normal file
2
sources-gen/assets/svg/icon-course-cert-gray.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/icon-course-cert-gray.0fdcab0c.svg";
|
42
sources-gen/assets/svg/icon-hint-circle-orange.svg.js
Normal file
42
sources-gen/assets/svg/icon-hint-circle-orange.svg.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
function SvgIconHintCircleOrange(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
width: "18px",
|
||||||
|
height: "18px",
|
||||||
|
viewBox: "0 0 18 18",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
xmlnsXlink: "http://www.w3.org/1999/xlink",
|
||||||
|
xmlSpace: "preserve",
|
||||||
|
style: {
|
||||||
|
fillRule: "evenodd",
|
||||||
|
clipRule: "evenodd",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
strokeMiterlimit: 1.41421
|
||||||
|
},
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M9,0C13.967,0 18,4.033 18,9C18,13.967 13.967,18 9,18C4.033,18 0,13.967 0,9C0,4.033 4.033,0 9,0ZM12.189,14.994L12.189,14.343L10.027,13.623L10.027,6.966C8.269,6.966 7.525,7.069 6.206,7.289L6.206,7.903C7.113,8.041 7.538,8.144 7.977,8.337L7.977,13.657C7.181,13.849 6.502,14.013 5.87,14.343L5.87,14.994L12.189,14.994ZM8.984,5.417C8.544,5.417 8.31,5.322 8.007,5.02C7.705,4.718 7.61,4.484 7.61,4.044C7.61,3.605 7.705,3.37 8.007,3.068C8.31,2.765 8.544,2.67 8.984,2.67C9.424,2.67 9.657,2.765 9.96,3.068C10.262,3.37 10.357,3.605 10.357,4.044C10.357,4.484 10.262,4.718 9.96,5.02C9.657,5.322 9.424,5.417 8.984,5.417Z",
|
||||||
|
style: {
|
||||||
|
fill: "#f08c00"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgIconHintCircleOrange);
|
||||||
|
export default __webpack_public_path__ + "static/media/icon-hint-circle-orange.764164ab.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
39
sources-gen/assets/svg/icon-hint.svg.js
Normal file
39
sources-gen/assets/svg/icon-hint.svg.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
function SvgIconHint(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
width: "10px",
|
||||||
|
height: "18px",
|
||||||
|
viewBox: "0 0 10 18",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
xmlnsXlink: "http://www.w3.org/1999/xlink",
|
||||||
|
style: {
|
||||||
|
fillRule: "evenodd"
|
||||||
|
},
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M369.101562,1457.80899 L369.101562,1456.85041 C369.918135,1456.42437 370.841202,1456.08709 371.870793,1455.83857 L371.870793,1448.22319 C371.302743,1447.97467 370.432929,1447.76165 369.261326,1447.58413 L369.261326,1446.67881 C370.965476,1446.39478 372.953622,1446.25277 375.225823,1446.25277 L375.225823,1455.83857 L378.101562,1456.85041 L378.101562,1457.80899 L369.101562,1457.80899 Z M373.308663,1444.17585 C372.740613,1444.17585 372.261328,1443.98059 371.870793,1443.59005 C371.480259,1443.19952 371.284994,1442.72023 371.284994,1442.15218 C371.284994,1441.58413 371.480259,1441.10485 371.870793,1440.71431 C372.261328,1440.32378 372.740613,1440.12851 373.308663,1440.12851 C373.876713,1440.12851 374.355998,1440.32378 374.746533,1440.71431 C375.137067,1441.10485 375.332332,1441.58413 375.332332,1442.15218 C375.332332,1442.72023 375.137067,1443.19952 374.746533,1443.59005 C374.355998,1443.98059 373.876713,1444.17585 373.308663,1444.17585 L373.308663,1444.17585 Z",
|
||||||
|
style: {
|
||||||
|
fill: "#f08c00"
|
||||||
|
},
|
||||||
|
transform: "translate(-369.000000, -1440.000000)"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgIconHint);
|
||||||
|
export default __webpack_public_path__ + "static/media/icon-hint.484f8f25.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
43
sources-gen/assets/svg/icon-language-world-w.svg.js
Normal file
43
sources-gen/assets/svg/icon-language-world-w.svg.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
function SvgIconLanguageWorldW(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
width: "16px",
|
||||||
|
height: "16px",
|
||||||
|
viewBox: "0 0 16 16",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
xmlnsXlink: "http://www.w3.org/1999/xlink",
|
||||||
|
xmlSpace: "preserve",
|
||||||
|
style: {
|
||||||
|
fillRule: "evenodd",
|
||||||
|
clipRule: "evenodd",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
strokeMiterlimit: 1.41421
|
||||||
|
},
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M7.976,0.026c-1.443,0 -2.784,0.36 -4.021,1.082c-1.208,0.707 -2.165,1.665 -2.872,2.873c-0.722,1.252 -1.083,2.599 -1.083,4.043c0,1.443 0.361,2.784 1.083,4.021c0.707,1.208 1.664,2.165 2.872,2.872c1.237,0.722 2.578,1.083 4.021,1.083c1.444,0 2.784,-0.361 4.021,-1.083c1.208,-0.707 2.166,-1.664 2.873,-2.872c0.736,-1.237 1.104,-2.578 1.104,-4.021c0,-1.444 -0.36,-2.784 -1.082,-4.021c-0.707,-1.208 -1.665,-2.166 -2.873,-2.873c-1.252,-0.736 -2.599,-1.104 -4.043,-1.104Zm3.005,6.451c1.208,-0.25 2.268,-0.641 3.182,-1.171c0.383,0.855 0.574,1.76 0.574,2.718c0,1.149 -0.272,2.209 -0.817,3.181c-0.973,-0.486 -1.974,-0.832 -3.005,-1.038c0.088,-0.692 0.132,-1.407 0.132,-2.143c0,-0.53 -0.022,-1.046 -0.066,-1.547Zm2.629,-2.165c-0.942,0.398 -1.878,0.677 -2.806,0.84c-0.25,-1.429 -0.648,-2.659 -1.193,-3.69c0.825,0.206 1.584,0.556 2.276,1.049c0.692,0.494 1.267,1.094 1.723,1.801Zm-3.734,3.712c0,0.781 -0.037,1.429 -0.11,1.944c-0.634,-0.073 -1.23,-0.11 -1.79,-0.11c-0.56,0 -1.156,0.037 -1.789,0.11c-0.074,-0.692 -0.111,-1.34 -0.111,-1.944c0,-0.309 0.015,-0.759 0.044,-1.348c0.516,0.074 1.138,0.111 1.867,0.111c0.729,0 1.344,-0.037 1.845,-0.111c0.03,0.589 0.044,1.039 0.044,1.348Zm-1.414,-6.739c0.589,1.178 0.995,2.526 1.215,4.043c-0.736,0.059 -1.303,0.089 -1.701,0.089c-0.398,0 -0.965,-0.03 -1.701,-0.089c0.236,-1.517 0.641,-2.865 1.215,-4.043c0.103,-0.015 0.265,-0.022 0.486,-0.022c0.221,0 0.383,0.007 0.486,0.022Zm-2.121,0.177c-0.56,1.09 -0.957,2.32 -1.193,3.69c-0.972,-0.192 -1.907,-0.472 -2.806,-0.84c0.471,-0.707 1.05,-1.307 1.734,-1.801c0.685,-0.493 1.44,-0.843 2.265,-1.049Zm-4.551,3.844c0.942,0.53 2.003,0.921 3.181,1.171c-0.044,0.501 -0.066,1.017 -0.066,1.547c0,0.736 0.044,1.451 0.133,2.143c-1.032,0.206 -2.033,0.552 -3.005,1.038c-0.531,-0.986 -0.796,-2.047 -0.796,-3.181c0,-0.943 0.184,-1.849 0.553,-2.718Zm0.906,6.894c0.824,-0.324 1.679,-0.56 2.563,-0.707c0.235,1.119 0.596,2.143 1.082,3.071c-0.722,-0.192 -1.395,-0.49 -2.021,-0.895c-0.627,-0.405 -1.168,-0.895 -1.624,-1.469Zm4.794,2.541c-0.486,-0.973 -0.854,-2.114 -1.105,-3.425c0.531,-0.044 1.068,-0.066 1.613,-0.066c0.545,0 1.068,0.022 1.569,0.066c-0.25,1.311 -0.619,2.452 -1.105,3.425c-0.103,0.014 -0.265,0.022 -0.486,0.022c-0.221,0 -0.383,-0.008 -0.486,-0.022Zm2.121,-0.177c0.486,-0.928 0.847,-1.952 1.083,-3.071c0.898,0.147 1.76,0.383 2.585,0.707c-0.471,0.589 -1.02,1.086 -1.646,1.491c-0.626,0.405 -1.3,0.696 -2.022,0.873Z",
|
||||||
|
style: {
|
||||||
|
fill: "#fff",
|
||||||
|
fillRule: "nonzero"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgIconLanguageWorldW);
|
||||||
|
export default __webpack_public_path__ + "static/media/icon-language-world-w.bb8502bb.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
53
sources-gen/assets/svg/icon-user-navi.svg.js
Normal file
53
sources-gen/assets/svg/icon-user-navi.svg.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
var _ref2 = /*#__PURE__*/React.createElement("desc", null, "Person Icon");
|
||||||
|
|
||||||
|
var _ref3 = /*#__PURE__*/React.createElement("g", {
|
||||||
|
id: "Seiten",
|
||||||
|
stroke: "none",
|
||||||
|
strokeWidth: 1,
|
||||||
|
fill: "none",
|
||||||
|
fillRule: "evenodd",
|
||||||
|
opacity: 1
|
||||||
|
}, /*#__PURE__*/React.createElement("g", {
|
||||||
|
id: "06-desk-lektionsinfo+burger",
|
||||||
|
transform: "translate(-1146.000000, -501.000000)",
|
||||||
|
fill: "#FFFFFF"
|
||||||
|
}, /*#__PURE__*/React.createElement("g", {
|
||||||
|
id: "burgernavi-d",
|
||||||
|
transform: "translate(920.000000, 170.000000)"
|
||||||
|
}, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M241.86087,345.655072 C239.603853,344.603859 238.150728,344.078261 237.501449,344.078261 L233.976812,345.284058 L230.35942,344.078261 C230.081158,344.078261 229.578748,344.209661 228.852174,344.472464 C228.1256,344.735267 227.468602,344.990337 226.881159,345.237681 L226,345.655072 L226,347 L241.86087,347 L241.86087,345.655072 Z M229.988406,340.507246 C231.008701,342.64059 232.338156,343.707246 233.976812,343.707246 C235.584549,343.707246 236.898546,342.64059 237.918841,340.507246 C238.289857,340.383574 238.591303,339.997105 238.823188,339.347826 C239.055074,338.698547 239.155556,338.072467 239.124638,337.469565 C239.09372,336.866664 238.954591,336.565217 238.707246,336.565217 C239.047345,335.606758 239.047345,334.802902 238.707246,334.153623 C238.676328,334.060869 238.629952,333.944928 238.568116,333.805797 C238.50628,333.666666 238.343963,333.419325 238.081159,333.063768 C237.818356,332.708211 237.524639,332.391306 237.2,332.113043 C236.875361,331.834781 236.427056,331.579711 235.855072,331.347826 C235.283089,331.115941 234.657008,331 233.976812,331 C232.925599,331 231.998072,331.262799 231.194203,331.788406 C230.390334,332.314012 229.849277,332.839611 229.571014,333.365217 L229.2,334.153623 L229.153623,334.292754 C229.122705,334.35459 229.099517,334.455072 229.084058,334.594203 C229.068599,334.733334 229.05314,334.887922 229.037681,335.057971 C229.022222,335.22802 229.029952,335.444443 229.06087,335.707246 C229.091788,335.97005 229.138164,336.256037 229.2,336.565217 C228.952656,336.565217 228.813527,336.866664 228.782609,337.469565 C228.751691,338.072467 228.852173,338.698547 229.084058,339.347826 C229.315943,339.997105 229.617389,340.383574 229.988406,340.507246 L229.988406,340.507246 Z M230.127536,335.776812 C230.127536,335.684058 230.166183,335.591305 230.243478,335.498551 C230.320773,335.405797 230.552655,335.282126 230.93913,335.127536 C231.325606,334.972946 231.889851,335.05024 232.631884,335.35942 C233.373917,335.637683 234.085021,335.714976 234.765217,335.591304 C235.445414,335.467632 235.971013,335.313044 236.342029,335.127536 C236.713045,334.942028 236.991303,334.756523 237.176812,334.571014 C237.331402,334.571014 237.462801,334.764249 237.571014,335.150725 C237.679228,335.5372 237.733333,335.869564 237.733333,336.147826 L237.733333,337.353623 C237.918842,337.353623 238.042512,337.369082 238.104348,337.4 C238.166184,337.430918 238.197101,337.570047 238.197101,337.817391 C238.197101,338.064736 238.135266,338.435746 238.011594,338.930435 C237.733332,339.456041 237.455074,339.718841 237.176812,339.718841 C237.084058,339.966185 236.952658,340.259902 236.782609,340.6 C236.61256,340.940098 236.257008,341.403862 235.715942,341.991304 C235.174877,342.578747 234.595172,342.872464 233.976812,342.872464 C233.358451,342.872464 232.786476,342.609664 232.26087,342.084058 C231.735263,341.558451 231.364252,341.032853 231.147826,340.507246 L230.823188,339.718841 C230.699516,339.718841 230.560387,339.649276 230.405797,339.510145 C230.251207,339.371014 230.127537,339.239614 230.034783,339.115942 L229.895652,338.930435 C229.61739,337.879222 229.694684,337.353623 230.127536,337.353623 L230.127536,335.776812 Z",
|
||||||
|
id: "Shape"
|
||||||
|
}))));
|
||||||
|
|
||||||
|
function SvgIconUserNavi(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
width: "16px",
|
||||||
|
height: "16px",
|
||||||
|
viewBox: "0 0 16 16",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
xmlnsXlink: "http://www.w3.org/1999/xlink",
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title === undefined ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, "Avatar") : title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, _ref2, _ref3);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgIconUserNavi);
|
||||||
|
export default __webpack_public_path__ + "static/media/icon-user-navi.68643217.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
104
sources-gen/assets/svg/keyboard.svg.js
Normal file
104
sources-gen/assets/svg/keyboard.svg.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
var _ref2 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 2,
|
||||||
|
y: 6
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref3 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 5,
|
||||||
|
y: 6
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref4 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 8,
|
||||||
|
y: 6
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref5 = /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "m 11,6 3,0 0,5 -2,0 0,-3 -1,0 z"
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref6 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 12,
|
||||||
|
y: 12
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref7 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 6,
|
||||||
|
height: 2,
|
||||||
|
x: 5,
|
||||||
|
y: 12
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref8 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 9,
|
||||||
|
y: 9
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref9 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 6,
|
||||||
|
y: 9
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref10 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 2,
|
||||||
|
height: 2,
|
||||||
|
x: 2,
|
||||||
|
y: 12
|
||||||
|
});
|
||||||
|
|
||||||
|
var _ref11 = /*#__PURE__*/React.createElement("rect", {
|
||||||
|
width: 3,
|
||||||
|
height: 2,
|
||||||
|
x: 2,
|
||||||
|
y: 9
|
||||||
|
});
|
||||||
|
|
||||||
|
function SvgKeyboard(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
style: {
|
||||||
|
fill: "#888"
|
||||||
|
},
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("path", {
|
||||||
|
style: {
|
||||||
|
fill: "none",
|
||||||
|
stroke: "#888"
|
||||||
|
},
|
||||||
|
d: "M 0.5,4.5 15.5,4.5 15.5,15.5 0.5,15.5 Z"
|
||||||
|
}), _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _ref10, _ref11));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgKeyboard);
|
||||||
|
export default __webpack_public_path__ + "static/media/keyboard.3a060932.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
2
sources-gen/assets/svg/nav-cross-black-lg.svg.js
Normal file
2
sources-gen/assets/svg/nav-cross-black-lg.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/nav-cross-black-lg.4c2e3c0d.svg";
|
2
sources-gen/assets/svg/nav-cross-black-md.svg.js
Normal file
2
sources-gen/assets/svg/nav-cross-black-md.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/nav-cross-black-md.f5825c8f.svg";
|
2
sources-gen/assets/svg/nav-cross-lg.svg.js
Normal file
2
sources-gen/assets/svg/nav-cross-lg.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/nav-cross-lg.a759f43e.svg";
|
2
sources-gen/assets/svg/nav-cross-xs.svg.js
Normal file
2
sources-gen/assets/svg/nav-cross-xs.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/nav-cross-xs.fec778ad.svg";
|
66
sources-gen/assets/svg/smiley-negative.svg.js
Normal file
66
sources-gen/assets/svg/smiley-negative.svg.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
function SvgSmileyNegative(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
viewBox: "0 0 55 54",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
xmlnsXlink: "http://www.w3.org/1999/xlink",
|
||||||
|
xmlSpace: "preserve",
|
||||||
|
style: {
|
||||||
|
fillRule: "evenodd",
|
||||||
|
clipRule: "evenodd",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
strokeMiterlimit: 1.41421
|
||||||
|
},
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, /*#__PURE__*/React.createElement("circle", {
|
||||||
|
className: "dot",
|
||||||
|
cx: 27.5,
|
||||||
|
cy: 27,
|
||||||
|
r: 27,
|
||||||
|
style: {
|
||||||
|
fill: "#A9A094"
|
||||||
|
}
|
||||||
|
}), /*#__PURE__*/React.createElement("g", {
|
||||||
|
id: "face"
|
||||||
|
}, /*#__PURE__*/React.createElement("circle", {
|
||||||
|
cx: 18.5,
|
||||||
|
cy: 18.5,
|
||||||
|
r: 3.5,
|
||||||
|
style: {
|
||||||
|
fill: "#fff"
|
||||||
|
}
|
||||||
|
}), /*#__PURE__*/React.createElement("circle", {
|
||||||
|
cx: 36.5,
|
||||||
|
cy: 18.5,
|
||||||
|
r: 3.5,
|
||||||
|
style: {
|
||||||
|
fill: "#fff"
|
||||||
|
}
|
||||||
|
}), /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M40.902,32.312l-26.41,5.613l0.624,2.935l26.41,-5.614l-0.624,-2.934Z",
|
||||||
|
style: {
|
||||||
|
fill: "#fff"
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgSmileyNegative);
|
||||||
|
export default __webpack_public_path__ + "static/media/smiley-negative.6c289ab6.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
57
sources-gen/assets/svg/smiley-positive.svg.js
Normal file
57
sources-gen/assets/svg/smiley-positive.svg.js
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
function SvgSmileyPositive(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
viewBox: "0 0 55 54",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
xmlnsXlink: "http://www.w3.org/1999/xlink",
|
||||||
|
xmlSpace: "preserve",
|
||||||
|
style: {
|
||||||
|
fillRule: "evenodd",
|
||||||
|
clipRule: "evenodd",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
strokeMiterlimit: 1.41421
|
||||||
|
},
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, /*#__PURE__*/React.createElement("circle", {
|
||||||
|
className: "dot",
|
||||||
|
cx: 27.5,
|
||||||
|
cy: 27,
|
||||||
|
r: 27,
|
||||||
|
style: {
|
||||||
|
fill: "#A9A094"
|
||||||
|
}
|
||||||
|
}), /*#__PURE__*/React.createElement("g", {
|
||||||
|
id: "face"
|
||||||
|
}, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M26.439,37.092l-11.313,-11.314l-2.829,2.829l11.314,11.313l2.828,-2.828Z",
|
||||||
|
style: {
|
||||||
|
fill: "#fff"
|
||||||
|
}
|
||||||
|
}), /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M39.874,18l-19.092,19.092l2.829,2.828l19.092,-19.092l-2.829,-2.828Z",
|
||||||
|
style: {
|
||||||
|
fill: "#fff"
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgSmileyPositive);
|
||||||
|
export default __webpack_public_path__ + "static/media/smiley-positive.3d91069e.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
2
sources-gen/assets/svg/star-gray.svg.js
Normal file
2
sources-gen/assets/svg/star-gray.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/star-gray.84ad33dd.svg";
|
2
sources-gen/assets/svg/star-white.svg.js
Normal file
2
sources-gen/assets/svg/star-white.svg.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
export default __webpack_public_path__ + "static/media/star-white.d32dc96a.svg";
|
41
sources-gen/assets/svg/tick.svg.js
Normal file
41
sources-gen/assets/svg/tick.svg.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
var _ref2 = /*#__PURE__*/React.createElement("g", {
|
||||||
|
fill: "none",
|
||||||
|
fillRule: "evenodd"
|
||||||
|
}, /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M-2.5-2.5h17v17h-17z"
|
||||||
|
}), /*#__PURE__*/React.createElement("path", {
|
||||||
|
fill: "#FFF",
|
||||||
|
d: "M12.906 1.219C7.434 4.9 5.47 10.25 5.47 10.25H4.406S2.581 7.472.688 6.531l.53-1.062c2.089.469 3.72 1.593 3.72 1.593s1.78-3.61 7.437-6.906l.531 1.063z"
|
||||||
|
}), /*#__PURE__*/React.createElement("path", {
|
||||||
|
d: "M-4 16h20V-4H-4z"
|
||||||
|
}));
|
||||||
|
|
||||||
|
function SvgTick(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
width: 13,
|
||||||
|
height: 11,
|
||||||
|
viewBox: "0 0 13 11",
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, _ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgTick);
|
||||||
|
export default __webpack_public_path__ + "static/media/tick.adf0c598.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
37
sources-gen/assets/svg/toggleableArrow.svg.js
Normal file
37
sources-gen/assets/svg/toggleableArrow.svg.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
const __webpack_public_path__ = "https://learngerman.dw.com/";
|
||||||
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||||
|
|
||||||
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
var _ref2 = /*#__PURE__*/React.createElement("g", {
|
||||||
|
className: "arrowBox",
|
||||||
|
fillRule: "evenodd"
|
||||||
|
}, /*#__PURE__*/React.createElement("g", {
|
||||||
|
className: "arrowArrow",
|
||||||
|
transform: "translate(12, 12), rotate(0 0 0) scale(1.0)"
|
||||||
|
}, /*#__PURE__*/React.createElement("polygon", {
|
||||||
|
points: "12 -4.7125 0 4.9375 -12 -4.6875 -10.375 -5.5 0 0.125 10.375 -5.5"
|
||||||
|
})));
|
||||||
|
|
||||||
|
function SvgToggleableArrow(_ref, svgRef) {
|
||||||
|
var title = _ref.title,
|
||||||
|
titleId = _ref.titleId,
|
||||||
|
props = _objectWithoutProperties(_ref, ["title", "titleId"]);
|
||||||
|
|
||||||
|
return /*#__PURE__*/React.createElement("svg", _extends({
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
ref: svgRef,
|
||||||
|
"aria-labelledby": titleId
|
||||||
|
}, props), title ? /*#__PURE__*/React.createElement("title", {
|
||||||
|
id: titleId
|
||||||
|
}, title) : null, _ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForwardRef = /*#__PURE__*/React.forwardRef(SvgToggleableArrow);
|
||||||
|
export default __webpack_public_path__ + "static/media/toggleableArrow.a17a06a6.svg";
|
||||||
|
export { ForwardRef as ReactComponent };
|
23
sources-gen/components/Accordion/Accordion.jsx
Normal file
23
sources-gen/components/Accordion/Accordion.jsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { StyledAccordionItem as AccordionItem } from './AccordionItem/AccordionItem';
|
||||||
|
import { grammarOverviewColors } from '../../constants/grammarOverviewColors';
|
||||||
|
|
||||||
|
export const Accordion = ({ className, data }) => {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{data.map((accordionData, index) => (
|
||||||
|
<AccordionItem
|
||||||
|
key={accordionData.id}
|
||||||
|
backgroundColor={grammarOverviewColors[index % grammarOverviewColors.length]}
|
||||||
|
title={accordionData.headline}
|
||||||
|
contents={accordionData.grammars}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledAccordion = styled(Accordion)`
|
||||||
|
display: block;
|
||||||
|
`;
|
111
sources-gen/components/Accordion/AccordionItem/AccordionItem.jsx
Normal file
111
sources-gen/components/Accordion/AccordionItem/AccordionItem.jsx
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useToggle } from '../../../hooks/useToggle';
|
||||||
|
import { colors, resolutions } from '../../../utils/css';
|
||||||
|
import { StyledToggleableArrow as ToggleableArrow } from '../../ToggleableArrow/ToggleableArrow';
|
||||||
|
import { I18nText } from '../../I18n/I18nText';
|
||||||
|
import { getContentUrl } from '../../../utils/url/urlFactory';
|
||||||
|
|
||||||
|
export const AccordionItem = ({ title, contents, className }) => {
|
||||||
|
const element = useRef(null);
|
||||||
|
const [isOpen, { toggleOnClick }] = useToggle();
|
||||||
|
const height = element.current ? element.current.scrollHeight : '0';
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<button tabIndex={0} className="accordionItem-btn" onClick={toggleOnClick}>
|
||||||
|
<I18nText translation={title} isA="p" className={className} />
|
||||||
|
<ToggleableArrow
|
||||||
|
className="toggleable-arrow"
|
||||||
|
fill={colors.LG_WHITE}
|
||||||
|
{...{
|
||||||
|
isUp: isOpen,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<AccordionItemContent height={height} isOpen={isOpen} ref={element} aria-expanded={isOpen}>
|
||||||
|
{contents.map(content => (
|
||||||
|
<div key={content.id} className="accordionItem-text">
|
||||||
|
<Link
|
||||||
|
tabIndex={isOpen ? 0 : -1}
|
||||||
|
to={getContentUrl({
|
||||||
|
id: content.id,
|
||||||
|
name: content.shortTitle,
|
||||||
|
language: content.language,
|
||||||
|
__typename: content.knowledgeType,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{content.shortTitle}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</AccordionItemContent>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledAccordionItem = styled(AccordionItem)`
|
||||||
|
font-family: DWTheAntiquaB, Georgia, serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 25px;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0px;
|
||||||
|
|
||||||
|
.accordionItem-btn {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: ${({ backgroundColor }) => backgroundColor};
|
||||||
|
color: ${colors.LG_WHITE};
|
||||||
|
cursor: pointer;
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
:hover {
|
||||||
|
background-color: ${colors.LG_GRAY_9};
|
||||||
|
}
|
||||||
|
:focus {
|
||||||
|
color: ${colors.LG_BAHAMA_BLUE};
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleable-arrow {
|
||||||
|
right: 18px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const AccordionItemContent = styled.div`
|
||||||
|
max-height: ${({ isOpen, height }) => (isOpen ? height : '1')}px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: ${colors.LG_WHITE};
|
||||||
|
transition: max-height 0.7s;
|
||||||
|
|
||||||
|
.accordionItem-text {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 25px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-color: ${colors.LG_GRAY_12};
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: ${colors.LG_GRAY_9};
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 20px;
|
||||||
|
display: block;
|
||||||
|
&:hover {
|
||||||
|
color: ${colors.LG_WHITE};
|
||||||
|
background-color: ${colors.LG_GRAY_9};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
214
sources-gen/components/App.jsx
Normal file
214
sources-gen/components/App.jsx
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
import { Redirect, Route, Switch } from 'react-router-dom';
|
||||||
|
import { useParams } from 'react-router';
|
||||||
|
import { Default404Page } from '../pages/Default404Page';
|
||||||
|
import { urlPrefixToType } from '../utils/url/url';
|
||||||
|
import { CoursePage } from '../pages/CoursePage';
|
||||||
|
import { GrammarPage } from '../pages/GrammarPage';
|
||||||
|
import { DashboardPage } from '../pages/DashboardPage';
|
||||||
|
import { GrammarOverviewPage } from '../pages/GrammarOverviewPage';
|
||||||
|
import { pathPartials } from '../utils/url/pathAnalyser';
|
||||||
|
import { LessonPage } from '../pages/LessonPage';
|
||||||
|
import {
|
||||||
|
PAGE_GRAMMAR,
|
||||||
|
PAGE_LEGAL,
|
||||||
|
PAGE_OVERVIEW,
|
||||||
|
PAGE_PASSWORD_CHANGE,
|
||||||
|
PAGE_PASSWORD_RESET,
|
||||||
|
PAGE_PLACEMENT_TEST,
|
||||||
|
PAGE_PROFILE,
|
||||||
|
PAGE_REGISTRATION,
|
||||||
|
PAGE_VOCABULARY,
|
||||||
|
PAGE_VOCABULARY_TRAINER,
|
||||||
|
PAGE_VOCABULARY_TRAINER_START,
|
||||||
|
STATUS_FEEDBACK,
|
||||||
|
} from '../utils/url/urlFactory';
|
||||||
|
import { FEEDBACK_TYPES } from '../constants/feedback';
|
||||||
|
import { RestrictedRoute } from './RestrictedRoute/RestrictedRoute';
|
||||||
|
import { ConfirmUserRegistrationContainer } from './user/ConfirmUserRegistrationContainer';
|
||||||
|
import { Registration } from './user/Registration';
|
||||||
|
import { PasswordChange } from './user/PasswordChange';
|
||||||
|
import { PasswordReset } from './user/PasswordReset';
|
||||||
|
import { StatusFeedback } from './StatusFeedback/StatusFeedback';
|
||||||
|
import { PageContainer, withPageContainerAndMetadata } from './Page/PageContainer';
|
||||||
|
import { UserProfile } from './user/UserProfile';
|
||||||
|
import { SetNewPassword } from './user/SetNewPassword';
|
||||||
|
import { PlacementTestPage } from '../pages/PlacementTestPage';
|
||||||
|
import { VocabularyTrainer } from './VocabularyTrainer/VocabularyTrainer';
|
||||||
|
import { PlacementAndFinalTestResultPage } from '../pages/PlacementAndFinalTestResultPage';
|
||||||
|
import { HelpPage } from '../pages/HelpPage';
|
||||||
|
import { GTM_NO_CONTENT_PAGE_IDS, PAGE_TYPES } from '../constants/pageTypes';
|
||||||
|
import { PageMetaData } from './Page/PageMetaData';
|
||||||
|
import { LegalPage } from '../pages/LegalPage';
|
||||||
|
import { VocabularyPage } from '../pages/VocabularyPage';
|
||||||
|
import { GtmScriptWithDataLayer } from './GoogleTagManager';
|
||||||
|
|
||||||
|
const typeToPage = {
|
||||||
|
COURSE: {
|
||||||
|
type: 'Course',
|
||||||
|
component: CoursePage,
|
||||||
|
},
|
||||||
|
GRAMMAR: {
|
||||||
|
type: 'Grammar',
|
||||||
|
component: GrammarPage,
|
||||||
|
},
|
||||||
|
LESSON: {
|
||||||
|
type: 'Lesson',
|
||||||
|
component: LessonPage,
|
||||||
|
},
|
||||||
|
PLACEMENT: {
|
||||||
|
type: 'Placement',
|
||||||
|
component: PlacementAndFinalTestResultPage,
|
||||||
|
},
|
||||||
|
FINAL: {
|
||||||
|
type: 'Final',
|
||||||
|
component: PlacementAndFinalTestResultPage,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ContentPage = () => {
|
||||||
|
const params = useParams();
|
||||||
|
const pageDef = typeToPage[urlPrefixToType(params.typeId)];
|
||||||
|
const Tag = pageDef.component;
|
||||||
|
return <Tag {...params} type={pageDef.type} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const App = () => (
|
||||||
|
<Switch>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/"
|
||||||
|
render={() => (
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: '/en/overview',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_OVERVIEW}`}
|
||||||
|
component={DashboardPage}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})/:title(${pathPartials.titlePathRegex})?/l-:lessonId(${pathPartials.contentIdRegex})`}
|
||||||
|
component={LessonPage}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})/:title(${pathPartials.titlePathRegex})?/:typeId(${pathPartials.contentTypeRegex})-:contentId(${pathPartials.contentIdRegex})`}
|
||||||
|
component={ContentPage}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_GRAMMAR}`}
|
||||||
|
component={GrammarOverviewPage}
|
||||||
|
/>
|
||||||
|
<Route exact path={`/:langCode(${pathPartials.langCodeRegex})/help`} component={HelpPage} />
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_LEGAL}`}
|
||||||
|
component={LegalPage}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_VOCABULARY}`}
|
||||||
|
component={VocabularyPage}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_REGISTRATION}`}
|
||||||
|
render={() =>
|
||||||
|
withPageContainerAndMetadata({
|
||||||
|
component: Registration,
|
||||||
|
pageType: PAGE_TYPES.REGISTER_USER,
|
||||||
|
useDescriptionTranslation: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})/user/password/set`}
|
||||||
|
render={({ location }) => (
|
||||||
|
<PageContainer>
|
||||||
|
<PageMetaData pageType={PAGE_TYPES.PASSWORD_SET} addKeywordsAndDescription={false} />
|
||||||
|
<GtmScriptWithDataLayer noContentPageId={GTM_NO_CONTENT_PAGE_IDS.PASSWORD_SET} />
|
||||||
|
<SetNewPassword
|
||||||
|
confirmationId={new URLSearchParams(location.search).get('confirmationId')}
|
||||||
|
/>
|
||||||
|
</PageContainer>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})/user/register/confirm`}
|
||||||
|
render={({ location }) => (
|
||||||
|
<ConfirmUserRegistrationContainer
|
||||||
|
confirmationId={new URLSearchParams(location.search).get('confirmationId')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<RestrictedRoute
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_PROFILE}`}
|
||||||
|
render={() =>
|
||||||
|
withPageContainerAndMetadata({
|
||||||
|
component: UserProfile,
|
||||||
|
pageType: PAGE_TYPES.USER_PROFILE,
|
||||||
|
addDescriptionAndKeywordsMeta: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
feedbackType={FEEDBACK_TYPES.MISSING_USER_PROFILE}
|
||||||
|
/>
|
||||||
|
<RestrictedRoute
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_PASSWORD_CHANGE}`}
|
||||||
|
render={() =>
|
||||||
|
withPageContainerAndMetadata({
|
||||||
|
component: PasswordChange,
|
||||||
|
pageType: PAGE_TYPES.PASSWORD_CHANGE,
|
||||||
|
addDescriptionAndKeywordsMeta: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<RestrictedRoute
|
||||||
|
exact
|
||||||
|
path={[
|
||||||
|
`/:langCode(${pathPartials.langCodeRegex})${PAGE_VOCABULARY_TRAINER}`,
|
||||||
|
`/:langCode(${pathPartials.langCodeRegex})${PAGE_VOCABULARY_TRAINER_START}`,
|
||||||
|
]}
|
||||||
|
render={() =>
|
||||||
|
withPageContainerAndMetadata({
|
||||||
|
component: VocabularyTrainer,
|
||||||
|
pageType: PAGE_TYPES.VOCABULARY_TRAINER,
|
||||||
|
addDescriptionAndKeywordsMeta: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_PASSWORD_RESET}`}
|
||||||
|
render={() =>
|
||||||
|
withPageContainerAndMetadata({
|
||||||
|
component: PasswordReset,
|
||||||
|
pageType: PAGE_TYPES.PASSWORD_RESET,
|
||||||
|
addDescriptionAndKeywordsMeta: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${STATUS_FEEDBACK}/:feedbackType(${pathPartials.feedbackTypes})`}
|
||||||
|
render={() =>
|
||||||
|
withPageContainerAndMetadata({
|
||||||
|
component: StatusFeedback,
|
||||||
|
pageType: PAGE_TYPES.FEEDBACK_STATUS,
|
||||||
|
addDescriptionAndKeywordsMeta: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/:langCode(${pathPartials.langCodeRegex})${PAGE_PLACEMENT_TEST}`}
|
||||||
|
component={PlacementTestPage}
|
||||||
|
/>
|
||||||
|
<Route exact path={`/:langCode(${pathPartials.langCodeRegex})`} component={Default404Page} />
|
||||||
|
<Route component={Default404Page} />
|
||||||
|
</Switch>
|
||||||
|
);
|
177
sources-gen/components/BurgerButton/BurgerButton.jsx
Normal file
177
sources-gen/components/BurgerButton/BurgerButton.jsx
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { colors, resolutions } from '../../utils/css';
|
||||||
|
import navCrossBlackMd from '../../assets/svg/nav-cross-black-md.svg';
|
||||||
|
import navCrossBlackLg from '../../assets/svg/nav-cross-black-lg.svg';
|
||||||
|
import navCrossXs from '../../assets/svg/nav-cross-xs.svg';
|
||||||
|
import navCrossLg from '../../assets/svg/nav-cross-lg.svg';
|
||||||
|
import { StyledIconBar as IconBar } from '../IconBar/IconBar';
|
||||||
|
|
||||||
|
export const BurgerButton = ({
|
||||||
|
isNavMenuOpen,
|
||||||
|
toggleIsNavMenuOpen,
|
||||||
|
setIsLanguageSubMenuOpen,
|
||||||
|
className,
|
||||||
|
}) => (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
toggleIsNavMenuOpen();
|
||||||
|
setIsLanguageSubMenuOpen(false);
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className={className}
|
||||||
|
data-toggle="collapse"
|
||||||
|
data-target="#nav-user-menu"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-controls="navbar"
|
||||||
|
aria-expanded={isNavMenuOpen}
|
||||||
|
>
|
||||||
|
{isNavMenuOpen && <span className="close-menu" />}
|
||||||
|
<span className="screen-reader-only">Toggle navigation</span>
|
||||||
|
|
||||||
|
{!isNavMenuOpen && (
|
||||||
|
<>
|
||||||
|
<IconBar />
|
||||||
|
<IconBar />
|
||||||
|
<IconBar />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const defaultHoverStyles = `
|
||||||
|
&:hover {
|
||||||
|
.close-menu {
|
||||||
|
background: url(${navCrossXs});
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
${IconBar} {
|
||||||
|
background-color: ${colors.LG_BLACK};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CSS parsed by a string helper function to return css string with styling blocks as arguments,
|
||||||
|
could not be tested with jest-styled-components.
|
||||||
|
It reads the media option correctly (media: (hover:hover)). But it throws an unknown error.
|
||||||
|
While using string templates passes with known media option.
|
||||||
|
*/
|
||||||
|
const mediaHoverDeviceDetection = `
|
||||||
|
@media (hover: hover) and (pointer: fine) {
|
||||||
|
${defaultHoverStyles}
|
||||||
|
}
|
||||||
|
@media (hover: none) and (pointer: coarse) {
|
||||||
|
${defaultHoverStyles}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const closeMenuMobile = `
|
||||||
|
height: 12px;
|
||||||
|
width: 13px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const closeMenuTablet = `
|
||||||
|
height: 21px;
|
||||||
|
width: 22px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledBurgerButton = styled(BurgerButton)`
|
||||||
|
z-index: 3000;
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
padding: 0;
|
||||||
|
/*! @noflip */
|
||||||
|
right: 20px;
|
||||||
|
top: 13px;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
top: 20px;
|
||||||
|
&:hover {
|
||||||
|
.close-menu {
|
||||||
|
${closeMenuMobile}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: ${resolutions.min.tablet}px) and (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
top: 28px;
|
||||||
|
&:hover {
|
||||||
|
.close-menu {
|
||||||
|
${closeMenuTablet}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: ${resolutions.min.desktop}px) {
|
||||||
|
margin-top: 32px;
|
||||||
|
z-index: 1;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
/*! @noflip */
|
||||||
|
right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
${mediaHoverDeviceDetection}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 0;
|
||||||
|
.close-menu {
|
||||||
|
background: url(${navCrossBlackLg});
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-menu {
|
||||||
|
background: url(${navCrossLg});
|
||||||
|
display: block;
|
||||||
|
height: 21px;
|
||||||
|
margin-top: 5px;
|
||||||
|
/*! @noflip */
|
||||||
|
right: 15px;
|
||||||
|
width: 22px;
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.min.desktop}px) {
|
||||||
|
background: url(${navCrossXs});
|
||||||
|
height: 12px;
|
||||||
|
width: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: ${resolutions.min.tablet}px) and (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
background: url(${navCrossBlackMd});
|
||||||
|
height: 21px;
|
||||||
|
margin-top: 5px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: ${resolutions.min.desktop}px) {
|
||||||
|
background: url(${navCrossBlackMd});
|
||||||
|
height: 21px;
|
||||||
|
margin-top: 0px;
|
||||||
|
position: absolute;
|
||||||
|
/*! @noflip */
|
||||||
|
right: 0px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-reader-only {
|
||||||
|
border: none;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
`;
|
44
sources-gen/components/Checkbox/Checkbox.jsx
Normal file
44
sources-gen/components/Checkbox/Checkbox.jsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { hasErrorClassAssigner } from '../../utils/errorClassAssigner';
|
||||||
|
import { getTranslatedValidationMessage } from '../../utils/validation/validationMessages';
|
||||||
|
import { useI18nContext } from '../../context/I18nContext';
|
||||||
|
|
||||||
|
export const Checkbox = ({
|
||||||
|
name,
|
||||||
|
labelText,
|
||||||
|
validationErrorTranslationKey,
|
||||||
|
register,
|
||||||
|
validationError,
|
||||||
|
...restProps
|
||||||
|
}) => {
|
||||||
|
const { i18n } = useI18nContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="custom-checkbox">
|
||||||
|
<div className={hasErrorClassAssigner('form-group', validationError)}>
|
||||||
|
<div className="input-group">
|
||||||
|
<span className="input-group-addon">
|
||||||
|
<input
|
||||||
|
className="form-control"
|
||||||
|
name={name}
|
||||||
|
type="checkbox"
|
||||||
|
aria-label={name}
|
||||||
|
{...register}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<label className="checkbox-label">{labelText}</label>
|
||||||
|
</div>
|
||||||
|
{validationError && (
|
||||||
|
<small className="help-block">
|
||||||
|
{getTranslatedValidationMessage({
|
||||||
|
name,
|
||||||
|
validationErrorTranslationKey,
|
||||||
|
validationType: validationError.type,
|
||||||
|
t: i18n.t,
|
||||||
|
})}
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,53 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { useToggle } from '../../hooks/useToggle';
|
||||||
|
import { StyledToggleableArrow as ToggleableArrow } from '../ToggleableArrow/ToggleableArrow';
|
||||||
|
import { colors } from '../../utils/css';
|
||||||
|
import { useTranslation } from '../../hooks/useTranslation';
|
||||||
|
|
||||||
|
export const AccordionContainer = ({ title, children, className }) => {
|
||||||
|
const titleTranslation = useTranslation(title);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<details className={className}>
|
||||||
|
<summary className="row noVMargins">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8">
|
||||||
|
<h4>
|
||||||
|
{titleTranslation}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
<AccordionContainerContent
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AccordionContainerContent>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AccordionContainerContent = styled.div`
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: ${colors.LG_WHITE};
|
||||||
|
transition: max-height 0.7s;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledAccordionContainer = styled(AccordionContainer)`
|
||||||
|
button {
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
background-color: ${colors.LG_WHITE};
|
||||||
|
width: 10em;
|
||||||
|
}
|
||||||
|
.toggleable-arrow {
|
||||||
|
position: relative;
|
||||||
|
top: 0.1em;
|
||||||
|
margin-left: 0.2em;
|
||||||
|
width: 20px;
|
||||||
|
height: 17px;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,70 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { useToggle } from '../../hooks/useToggle';
|
||||||
|
import { StyledToggleableArrow as ToggleableArrow } from '../ToggleableArrow/ToggleableArrow';
|
||||||
|
import { colors } from '../../utils/css';
|
||||||
|
import { useTranslation } from '../../hooks/useTranslation';
|
||||||
|
|
||||||
|
export const AccordionContainer = ({ title, children, className }) => {
|
||||||
|
const element = useRef(null);
|
||||||
|
const [isOpen, { toggleOnClick }] = useToggle();
|
||||||
|
const height = element.current ? element.current.scrollHeight : '0';
|
||||||
|
const titleTranslation = useTranslation(title);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<div className="row noVMargins">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8">
|
||||||
|
<button tabIndex={0} onClick={toggleOnClick}>
|
||||||
|
<h4>
|
||||||
|
{titleTranslation}
|
||||||
|
<ToggleableArrow
|
||||||
|
className="toggleable-arrow"
|
||||||
|
fill={colors.LG_BLACK}
|
||||||
|
{...{
|
||||||
|
isUp: isOpen,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</h4>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AccordionContainerContent
|
||||||
|
height={height}
|
||||||
|
isOpen={isOpen}
|
||||||
|
ref={element}
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AccordionContainerContent>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AccordionContainerContent = styled.div`
|
||||||
|
max-height: ${({ isOpen, height }) => (isOpen ? height : '1')}px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: ${colors.LG_WHITE};
|
||||||
|
transition: max-height 0.7s;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledAccordionContainer = styled(AccordionContainer)`
|
||||||
|
button {
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
background-color: ${colors.LG_WHITE};
|
||||||
|
width: 10em;
|
||||||
|
}
|
||||||
|
.toggleable-arrow {
|
||||||
|
position: relative;
|
||||||
|
top: 0.1em;
|
||||||
|
margin-left: 0.2em;
|
||||||
|
width: 20px;
|
||||||
|
height: 17px;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const ContentBottomLine = () => (
|
||||||
|
<div className="row vocabulary list-end">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8 vocabulary-entry" />
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { ContentNavTitle } from './ContentNavTitle/ContentNavTitle';
|
||||||
|
|
||||||
|
export const ContentContainer = ({ title, children }) => (
|
||||||
|
<div className="section exercise-container vocabulary copy">
|
||||||
|
<ContentNavTitle {...{ title, top: true }} />
|
||||||
|
{children}
|
||||||
|
<ContentNavTitle {...{ title, bottom: true }} />
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -0,0 +1,13 @@
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
export const ContentHeadline = ({ children, isStandalone = false }) => {
|
||||||
|
return (
|
||||||
|
<div className="headline-container row">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8 ">
|
||||||
|
<div className={classnames('exercise-headline', { standalone: isStandalone })}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { I18nText } from '../../I18n/I18nText';
|
||||||
|
|
||||||
|
export const ContentNavTitle = ({ title, top, bottom }) => (
|
||||||
|
<div className="row noVMargins">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8">
|
||||||
|
<div
|
||||||
|
className={classnames('exercise-nav', {
|
||||||
|
top,
|
||||||
|
bottom,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<I18nText
|
||||||
|
isA="div"
|
||||||
|
className="exercise-nav-title"
|
||||||
|
style={{ direction: 'ltr' }}
|
||||||
|
translation={title}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { I18nText } from '../../I18n/I18nText';
|
||||||
|
|
||||||
|
export const ContentSection = ({ title, children }) => (
|
||||||
|
<>
|
||||||
|
<div className="row vocabulary">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8">
|
||||||
|
<I18nText isA="h3" translation={title} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row vocabulary">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8">
|
||||||
|
<div className="richtext-content-container">{children}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
|
@ -0,0 +1,69 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { StyledHeroTemplate as HeroTemplate } from '../../HeroTemplate/HeroTemplate';
|
||||||
|
import { resolutions } from '../../../utils/css';
|
||||||
|
|
||||||
|
const determineImage = ({ imageId, imageBasePath }) => {
|
||||||
|
return `${imageBasePath}/${imageId}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledCourseHeroImage = styled(HeroTemplate)`
|
||||||
|
background: url(${determineImage}_509.jpg) center center / cover no-repeat;
|
||||||
|
height: 320px;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.identifier {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font: 700 40px Helvetica, Arial, sans-serif;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
/* @noflip */
|
||||||
|
direction: ltr;
|
||||||
|
font: 400 40px DWTheAntiquaB, Georgia, serif;
|
||||||
|
opacity: 1;
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
.identifier,
|
||||||
|
.description {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
background: url(${determineImage}_507.jpg) center center / cover no-repeat;
|
||||||
|
|
||||||
|
.identifier,
|
||||||
|
.description {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
.identifier,
|
||||||
|
.description {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
background: url(${determineImage}_503.jpg) center center / cover no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 360px) {
|
||||||
|
background: url(${determineImage}_501.jpg) center center / cover no-repeat;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { resolutions } from '../../../../utils/css';
|
||||||
|
import { useToggle } from '../../../../hooks/useToggle';
|
||||||
|
import { StyledCourseHeader as CourseHeader } from '../CourseHeader/CourseHeader';
|
||||||
|
import { StyledLessonList as LessonList } from '../LessonList/LessonList';
|
||||||
|
import globals from '../../../../utils/globals';
|
||||||
|
|
||||||
|
export const CourseAccordion = ({ groupNameTranslationKey, groupedLessons, onClickReset }) => {
|
||||||
|
const isOnDesktop = globals.window.innerWidth >= resolutions.min.desktop;
|
||||||
|
const [isOpen, { toggleOnClick, toggleOnKeyPress }] = useToggle({ initialState: isOnDesktop });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="accordion" aria-label="course.accordion">
|
||||||
|
<CourseHeader
|
||||||
|
{...{
|
||||||
|
isOpen,
|
||||||
|
groupNameTranslationKey,
|
||||||
|
onClick: toggleOnClick,
|
||||||
|
onKeyPress: toggleOnKeyPress,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<LessonList
|
||||||
|
{...{
|
||||||
|
isOpen,
|
||||||
|
groupedLessons,
|
||||||
|
onClickReset,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,78 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { I18nText } from '../../../I18n/I18nText';
|
||||||
|
import { colors, resolutions } from '../../../../utils/css';
|
||||||
|
import { StyledToggleableArrow as ToggleableArrow } from '../../../ToggleableArrow/ToggleableArrow';
|
||||||
|
|
||||||
|
const CourseHeader = ({ className, groupNameTranslationKey, isOpen, onClick, onKeyPress }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames(className, 'header')}
|
||||||
|
role="button"
|
||||||
|
tabIndex="0"
|
||||||
|
onClick={onClick}
|
||||||
|
onKeyPress={onKeyPress}
|
||||||
|
aria-label="course.header"
|
||||||
|
>
|
||||||
|
<I18nText
|
||||||
|
className={classnames('title')}
|
||||||
|
{...{
|
||||||
|
isA: 'h2',
|
||||||
|
}}
|
||||||
|
aria-label="course.groupName"
|
||||||
|
translation={groupNameTranslationKey || 'course.otherLessons'}
|
||||||
|
/>
|
||||||
|
<ToggleableArrow
|
||||||
|
className="toggleable-arrow"
|
||||||
|
fill={colors.LG_GRAY_13}
|
||||||
|
{...{
|
||||||
|
isUp: isOpen,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledCourseHeader = styled(CourseHeader)`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid ${colors.LG_GRAY_TRANSPARENT_1};
|
||||||
|
height: 163px;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
height: 25px;
|
||||||
|
background-color: ${colors.LG_WHITE};
|
||||||
|
color: ${colors.LG_GRAY_13};
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 23px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleable-arrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
height: 94px;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding: 0 45px 0 20px;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleable-arrow {
|
||||||
|
display: inline-block;
|
||||||
|
right: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
48
sources-gen/components/Course/CourseList/CourseList.jsx
Normal file
48
sources-gen/components/Course/CourseList/CourseList.jsx
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { colors, resolutions } from '../../../utils/css';
|
||||||
|
import { CourseAccordion } from './CourseAccordion/CourseAccordion';
|
||||||
|
|
||||||
|
export const CourseList = ({ className, groupedLessons, onClickResetLesson }) => (
|
||||||
|
<ul className={className} aria-label="course.list">
|
||||||
|
{Object.keys(groupedLessons).map(key => (
|
||||||
|
// group lessons by their group names
|
||||||
|
<li key={groupedLessons[key][0].id} className="course">
|
||||||
|
<CourseAccordion
|
||||||
|
{...{
|
||||||
|
groupNameTranslationKey: groupedLessons[key][0].groupName,
|
||||||
|
groupedLessons: groupedLessons[key],
|
||||||
|
onClickReset: onClickResetLesson,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const StyledCourseList = styled(CourseList)`
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
width: 100%;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.course {
|
||||||
|
display: inline-block;
|
||||||
|
background: ${colors.LG_WHITE};
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
.accordion .lesson-list {
|
||||||
|
background-color: ${colors.LG_GRAY_3};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,120 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { StyledText as Text } from '../../../Text/Text';
|
||||||
|
import { colors } from '../../../../utils/css';
|
||||||
|
import { getContentUrl } from '../../../../utils/url/urlFactory';
|
||||||
|
import { StyledLessonScore as LessonScore } from './LessonScore';
|
||||||
|
import { StyledSmallProgressResetButton as ProgressResetButton } from '../../Progress/ProgressResetButton';
|
||||||
|
import { LearnProgressIcon } from '../../../LearnProgressIcon/LearnProgressIcon';
|
||||||
|
import { findLessonLearnProgressSelector } from '../../../../state/progress/learnProgressSelectors';
|
||||||
|
|
||||||
|
export const LessonItem = ({ lesson, className, onClickReset }) => {
|
||||||
|
const lessonId = lesson.id;
|
||||||
|
const lessonProgress = useSelector(findLessonLearnProgressSelector(lessonId));
|
||||||
|
|
||||||
|
const onHandleResetClick = e => {
|
||||||
|
onClickReset(e, lessonId);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Link
|
||||||
|
className={className}
|
||||||
|
to={getContentUrl({
|
||||||
|
id: lesson.id,
|
||||||
|
name: lesson.shortTitle,
|
||||||
|
language: lesson.language,
|
||||||
|
__typename: 'Lesson',
|
||||||
|
})}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<Text className="title" isA="h3" aria-label="lesson.title">
|
||||||
|
{lesson.shortTitle}
|
||||||
|
</Text>
|
||||||
|
<div className={`tile-progress`}>
|
||||||
|
<LearnProgressIcon learnProgress={lessonProgress} />
|
||||||
|
</div>
|
||||||
|
<Text className="learningTarget" aria-label="lesson.learningTarget">
|
||||||
|
{lesson.learningTargetHeadline}
|
||||||
|
</Text>
|
||||||
|
{lessonProgress && (
|
||||||
|
<>
|
||||||
|
<LessonScore
|
||||||
|
className="lessonScore"
|
||||||
|
lessonProgress={lessonProgress}
|
||||||
|
onClickReset={onClickReset}
|
||||||
|
lessonId={lesson.id}
|
||||||
|
/>
|
||||||
|
<ProgressResetButton className="resetButton" onClickReset={onHandleResetClick} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Text className="categories" aria-label="lesson.categories">
|
||||||
|
{lesson.grammarDescription}
|
||||||
|
</Text>
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const alignProgressData = '5px';
|
||||||
|
|
||||||
|
export const StyledLessonItem = styled(LessonItem)`
|
||||||
|
border-top: 1px solid ${colors.LG_GRAY_TRANSPARENT_1};
|
||||||
|
color: ${colors.LG_GRAY_8};
|
||||||
|
display: grid;
|
||||||
|
font-size: 14px;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
grid-template-rows: repeat(3, 1fr);
|
||||||
|
height: 102px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
overflow-y: hidden;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${colors.LG_GRAY_8};
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: ${colors.LG_GRAY_9};
|
||||||
|
font-family: DWTheAntiquaBBold, Georgia-Bold, serif;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.learningTarget,
|
||||||
|
.categories {
|
||||||
|
font-family: DWTheAntiquaB, Georgia, serif;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories {
|
||||||
|
grid-column: 1 / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-progress {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 5px 0 0 0;
|
||||||
|
padding-right: ${alignProgressData};
|
||||||
|
}
|
||||||
|
|
||||||
|
.lessonScore {
|
||||||
|
grid-column-start: 2;
|
||||||
|
justify-self: flex-end;
|
||||||
|
padding-right: ${alignProgressData};
|
||||||
|
}
|
||||||
|
|
||||||
|
.resetButton {
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-row-start: 3;
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,41 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { colors } from '../../../../utils/css';
|
||||||
|
import { calculatePercentage } from '../../../../utils/commons';
|
||||||
|
|
||||||
|
export const LessonScore = ({ className, lessonProgress }) => {
|
||||||
|
const { resultPoints, maxPointsForAllExercises } = lessonProgress;
|
||||||
|
|
||||||
|
const resultPointsClassName = () => {
|
||||||
|
const resultInPercentage = calculatePercentage(resultPoints, maxPointsForAllExercises);
|
||||||
|
|
||||||
|
if (resultInPercentage >= 70) {
|
||||||
|
return 'good';
|
||||||
|
}
|
||||||
|
if (resultInPercentage <= 40) {
|
||||||
|
return 'low';
|
||||||
|
}
|
||||||
|
return 'mid';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<span className={resultPointsClassName()}>{resultPoints}</span>
|
||||||
|
<span>/</span>
|
||||||
|
<span>{maxPointsForAllExercises}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledLessonScore = styled(LessonScore)`
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.low {
|
||||||
|
color: ${colors.LG_RED_SCORE};
|
||||||
|
}
|
||||||
|
.mid {
|
||||||
|
color: ${colors.LG_GRAY_11};
|
||||||
|
}
|
||||||
|
.good {
|
||||||
|
color: ${colors.LG_GREEN_SCORE};
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,47 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { colors, resolutions } from '../../../../utils/css';
|
||||||
|
import { StyledLessonItem as LessonItem } from '../LessionItem/LessonItem';
|
||||||
|
|
||||||
|
export const LessonList = ({ className, groupedLessons, onClickReset, isOpen = true }) => (
|
||||||
|
// eslint-disable-next-line jsx-a11y/role-supports-aria-props
|
||||||
|
<ul
|
||||||
|
className={classnames(className, 'lesson-list', { collapsed: !isOpen })}
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
aria-label="lesson.list"
|
||||||
|
>
|
||||||
|
{groupedLessons.map(lesson => (
|
||||||
|
<li key={lesson.id} className="lesson-item">
|
||||||
|
<LessonItem
|
||||||
|
{...{
|
||||||
|
lesson: lesson.target,
|
||||||
|
onClickReset,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const StyledLessonList = styled(LessonList)`
|
||||||
|
transition: max-height 0.3s linear;
|
||||||
|
overflow-y: hidden;
|
||||||
|
visibility: visible;
|
||||||
|
max-height: ${props => props.groupedLessons.length * 102}px;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
background-color: ${colors.LG_GRAY_3};
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
visibility: hidden;
|
||||||
|
max-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
140
sources-gen/components/Course/CourseOverview.jsx
Normal file
140
sources-gen/components/Course/CourseOverview.jsx
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { createGlobalStyle } from 'styled-components';
|
||||||
|
import {
|
||||||
|
groupBy,
|
||||||
|
isFinalTestPredicate,
|
||||||
|
removeContentLinksWithEmptyTarget,
|
||||||
|
} from '../../utils/commons';
|
||||||
|
import { useFrontendConfig } from '../../hooks/useFrontendConfig';
|
||||||
|
import {
|
||||||
|
deleteCourseProgress,
|
||||||
|
deleteLessonProgress,
|
||||||
|
initCourse,
|
||||||
|
readCourseProgress,
|
||||||
|
readLessonProgresses,
|
||||||
|
} from '../../state/progress/learnProgressDuck';
|
||||||
|
import { isMonolingualCourse } from '../../constants/isLtrContentOnly';
|
||||||
|
import { StyledCourseHeroImage as CoursePageHeroImage } from './CourseHeroImage/CourseHeroImage';
|
||||||
|
import { I18nText } from '../I18n/I18nText';
|
||||||
|
import { StyledCourseList as CourseList } from './CourseList/CourseList';
|
||||||
|
import { ModalIntegration } from '../Modal/ModalIntegration';
|
||||||
|
import { ResetModal } from '../Modal/ResetModal';
|
||||||
|
import { StyledCourseProgress as CourseProgress } from './Progress/CourseProgress';
|
||||||
|
import { learningLevelMapper } from '../../utils/learningLevelUtils';
|
||||||
|
|
||||||
|
export const LTRContentCourseOverviewStyle = createGlobalStyle`
|
||||||
|
#courses {
|
||||||
|
.title,
|
||||||
|
span[aria-label*="lesson"] {
|
||||||
|
/* @noflip */
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
.content .title {
|
||||||
|
/* @noflip */
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const CourseOverview = ({ data, contentId }) => {
|
||||||
|
const isMonoLingualCourse = isMonolingualCourse(contentId);
|
||||||
|
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
dkLearningLevel,
|
||||||
|
contentLinks: lessonContentLinks,
|
||||||
|
mainContentImageLink,
|
||||||
|
learningMetaInfo: { achievableScore, exerciseCount } = {},
|
||||||
|
} = data.content;
|
||||||
|
const filteredContentLinks = removeContentLinksWithEmptyTarget(lessonContentLinks);
|
||||||
|
const finalLessonId = filteredContentLinks
|
||||||
|
.filter(contentLink => isFinalTestPredicate(contentLink))
|
||||||
|
.map(contentLink => contentLink.target.id);
|
||||||
|
const allLessonIds = filteredContentLinks.map(contentLink => contentLink.target.id);
|
||||||
|
const groupedLessons = groupBy('groupName', filteredContentLinks);
|
||||||
|
const { imageBasePath } = useFrontendConfig();
|
||||||
|
const [isResetModalOpen, setResetModalOpen] = useState(false);
|
||||||
|
const [lessonIdToDelete, setLessonIdToDelete] = useState(null);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(
|
||||||
|
initCourse({
|
||||||
|
allExerciseCount: exerciseCount,
|
||||||
|
maxPointsForAllExercises: achievableScore,
|
||||||
|
cosCourseId: contentId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
dispatch(readLessonProgresses(allLessonIds));
|
||||||
|
dispatch(readCourseProgress(contentId));
|
||||||
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
|
const onClickResetCourse = () => {
|
||||||
|
setResetModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickResetLesson = (e, lessonId) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setLessonIdToDelete(lessonId);
|
||||||
|
setResetModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onConfirmResetProgress = () => {
|
||||||
|
if (lessonIdToDelete) {
|
||||||
|
dispatch(deleteLessonProgress(lessonIdToDelete));
|
||||||
|
setLessonIdToDelete(null);
|
||||||
|
} else {
|
||||||
|
dispatch(deleteCourseProgress(contentId));
|
||||||
|
}
|
||||||
|
setResetModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancelResetModal = () => {
|
||||||
|
setLessonIdToDelete(null);
|
||||||
|
setResetModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="section" data-course-id={contentId} id="courses">
|
||||||
|
{isMonoLingualCourse && <LTRContentCourseOverviewStyle />}
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-xs-12">
|
||||||
|
<div className="respHeaderImgContainer course-headline">
|
||||||
|
<CoursePageHeroImage
|
||||||
|
imageId={mainContentImageLink.targetId}
|
||||||
|
imageBasePath={imageBasePath}
|
||||||
|
>
|
||||||
|
<h1 className="title">
|
||||||
|
<I18nText
|
||||||
|
tabIndex={0}
|
||||||
|
translation={learningLevelMapper[dkLearningLevel]}
|
||||||
|
className="identifier"
|
||||||
|
/>
|
||||||
|
<I18nText tabIndex={0} translation={name} className="description" />
|
||||||
|
</h1>
|
||||||
|
</CoursePageHeroImage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<CourseProgress
|
||||||
|
courseId={+contentId}
|
||||||
|
finalLessonId={finalLessonId}
|
||||||
|
onClickResetCourse={onClickResetCourse}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="row course-list learn-status">
|
||||||
|
<CourseList {...{ groupedLessons, onClickResetLesson }} />
|
||||||
|
</div>
|
||||||
|
<ModalIntegration isOpen={isResetModalOpen}>
|
||||||
|
<ResetModal
|
||||||
|
fadeIn={true}
|
||||||
|
onConfirmClicked={onConfirmResetProgress}
|
||||||
|
onCancelClicked={onCancelResetModal}
|
||||||
|
/>
|
||||||
|
</ModalIntegration>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
27
sources-gen/components/Course/Progress/CourseProgress.jsx
Normal file
27
sources-gen/components/Course/Progress/CourseProgress.jsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { StyledProgressResetButton as ProgressResetButton } from './ProgressResetButton';
|
||||||
|
import { LearnProgressIcon } from '../../LearnProgressIcon/LearnProgressIcon';
|
||||||
|
import { findCourseLearnProgressSelector } from '../../../state/progress/learnProgressSelectors';
|
||||||
|
|
||||||
|
export const CourseProgress = ({ className, courseId, finalLessonId, onClickResetCourse }) => {
|
||||||
|
const { courseProgress } = useSelector(findCourseLearnProgressSelector(courseId));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<ProgressResetButton onClickReset={onClickResetCourse} />
|
||||||
|
<LearnProgressIcon learnProgress={courseProgress} finalLessonId={finalLessonId} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledCourseProgress = styled(CourseProgress)`
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 25px;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin: 14px;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,25 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { I18nText } from '../../I18n/I18nText';
|
||||||
|
import { colors } from '../../../utils/css';
|
||||||
|
|
||||||
|
export const ProgressResetButton = ({ className, onClickReset }) => {
|
||||||
|
return (
|
||||||
|
<button onClick={e => onClickReset(e)} className={className}>
|
||||||
|
<I18nText translation="course.reset" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledProgressResetButton = styled(ProgressResetButton)`
|
||||||
|
background-color: ${colors.LG_GRAY_2};
|
||||||
|
border: 1px solid transparent;
|
||||||
|
color: ${colors.LG_WHITE};
|
||||||
|
font-size: 12px;
|
||||||
|
min-height: 31px;
|
||||||
|
padding: 3px 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledSmallProgressResetButton = styled(StyledProgressResetButton)`
|
||||||
|
min-height: 27px;
|
||||||
|
padding: 1px 7px;
|
||||||
|
`;
|
29
sources-gen/components/Dashboard/Dashboard.jsx
Normal file
29
sources-gen/components/Dashboard/Dashboard.jsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { StyledMainHeroImage } from '../MainHeroImage/MainHeroImage';
|
||||||
|
import { StyledTiles } from './Tiles/Tiles';
|
||||||
|
import { I18nText } from '../I18n/I18nText';
|
||||||
|
import { readCourseProgresses } from '../../state/progress/learnProgressDuck';
|
||||||
|
|
||||||
|
export const Dashboard = ({ data }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const courseIds = data.map(course => course.id);
|
||||||
|
dispatch(readCourseProgresses(courseIds));
|
||||||
|
}, [data, dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main aria-label="dashboard">
|
||||||
|
<StyledMainHeroImage>
|
||||||
|
<I18nText isA="h1" tabIndex={0} translation="dashboard.title" className="title" />
|
||||||
|
<I18nText isA="p" tabIndex={0} translation="dashboard.subTitle" className="description" />
|
||||||
|
</StyledMainHeroImage>
|
||||||
|
<StyledTiles
|
||||||
|
{...{
|
||||||
|
data,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
28
sources-gen/components/Dashboard/Tiles/Tile/BlankTile.jsx
Normal file
28
sources-gen/components/Dashboard/Tiles/Tile/BlankTile.jsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { colors, resolutions } from '../../../../utils/css';
|
||||||
|
import { useRtlContext } from '../../../../hooks/useRtl';
|
||||||
|
|
||||||
|
const BlankTile = ({ className }) => {
|
||||||
|
const { isRtl } = useRtlContext();
|
||||||
|
return <div className={`${className} ${isRtl ? 'rtl' : ''}`} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledBlankTile = styled(BlankTile)`
|
||||||
|
border-top: 1px solid ${colors.LG_WHITE};
|
||||||
|
border-right: 1px solid ${colors.LG_WHITE};
|
||||||
|
background: ${colors.DW_LIGHT_BLUE};
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
height: 180px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.rtl {
|
||||||
|
border-right-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,23 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { StyledTile as Tile } from './Tile';
|
||||||
|
|
||||||
|
export const MoreCoursesTile = ({ className, backgroundColor }) => (
|
||||||
|
<Tile
|
||||||
|
{...{
|
||||||
|
className,
|
||||||
|
backgroundColor,
|
||||||
|
}}
|
||||||
|
data={{
|
||||||
|
dkLearningLevel: 0,
|
||||||
|
name: 'dashboard.dw.title',
|
||||||
|
subTitle: 'dashboard.dw.text',
|
||||||
|
href: 'https://www.dw.com/en/learn-german/s-2469', // TODO: to be added to config file
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const StyledMoreCoursesTile = styled(MoreCoursesTile)`
|
||||||
|
.tile-progress {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`;
|
186
sources-gen/components/Dashboard/Tiles/Tile/Tile.jsx
Normal file
186
sources-gen/components/Dashboard/Tiles/Tile/Tile.jsx
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import gql from 'graphql-tag';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { colors, resolutions } from '../../../../utils/css';
|
||||||
|
import { I18nText } from '../../../I18n/I18nText';
|
||||||
|
import { learningLevelMapper } from '../../../../utils/learningLevelUtils';
|
||||||
|
import { getContentUrl } from '../../../../utils/url/urlFactory';
|
||||||
|
import { LearnProgressIcon } from '../../../LearnProgressIcon/LearnProgressIcon';
|
||||||
|
import { findCourseLearnProgressSelector } from '../../../../state/progress/learnProgressSelectors';
|
||||||
|
import { userSelector } from '../../../../state/user/userSelectors';
|
||||||
|
import { progressIconColors } from '../../../ProgressIcon/progressIconColors';
|
||||||
|
|
||||||
|
export const tileFragment = gql`
|
||||||
|
fragment Tile on Course {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
language
|
||||||
|
subTitle
|
||||||
|
dkLearningLevel
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Tile = ({ className, data }) => {
|
||||||
|
const { dkLearningLevel, name, subTitle, id } = data;
|
||||||
|
const { courseProgress } = useSelector(findCourseLearnProgressSelector(id));
|
||||||
|
const { isLoggedIn } = useSelector(userSelector);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LinkWrapper {...{ linkData: data, className }}>
|
||||||
|
{isLoggedIn && (
|
||||||
|
<div className="tile-progress">
|
||||||
|
<LearnProgressIcon learnProgress={courseProgress} color={progressIconColors.WHITE} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h2 className="tile-learningLevel">{learningLevelMapper[dkLearningLevel]}</h2>
|
||||||
|
<I18nText isA="p" translation={name} className="tile-name" aria-label="tile.placement.name" />
|
||||||
|
<I18nText
|
||||||
|
isA="p"
|
||||||
|
translation={subTitle}
|
||||||
|
className="tile-subTitle"
|
||||||
|
aria-label="tile.placement.subTitle"
|
||||||
|
/>
|
||||||
|
</LinkWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const LinkWrapper = ({ children, linkData, className }) => {
|
||||||
|
return linkData.href ? (
|
||||||
|
<a className={`${className} tile-container`} href={linkData.href}>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<Link key={linkData.id} className={`${className} tile-container`} to={getContentUrl(linkData)}>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledTile = styled(Tile)`
|
||||||
|
--absElemOffset: 84px;
|
||||||
|
padding: var(--absElemOffset) 20px 20px 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 300px;
|
||||||
|
height: 250px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
border-color: ${colors.LG_WHITE};
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px 1px 0 0;
|
||||||
|
background-color: ${({ backgroundColor }) => backgroundColor};
|
||||||
|
color: ${colors.LG_WHITE};
|
||||||
|
|
||||||
|
&:nth-child(4n) {
|
||||||
|
border-right-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tile-container {
|
||||||
|
text-decoration: none;
|
||||||
|
:hover,
|
||||||
|
:active,
|
||||||
|
:focus {
|
||||||
|
color: ${colors.LG_TRANSPARENT_WHITE_50};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-learningLevel {
|
||||||
|
font: 400 70px / var(--absElemOffset) Helvetica, Arial, sans-serif;
|
||||||
|
height: var(--absElemOffset);
|
||||||
|
text-align: start;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-name {
|
||||||
|
font: 400 23px/25px DWTheAntiquaBBold, Georgia, serif;
|
||||||
|
margin: 0 0 7px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-subTitle {
|
||||||
|
font: 400 16px/25px DWTheAntiquaB, Georgia, serif;
|
||||||
|
max-height: 60%;
|
||||||
|
opacity: 0.9;
|
||||||
|
max-width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-progress {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
padding-top: 20px;
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
height: var(--absElemOffset);
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
--absElemOffset: 64px;
|
||||||
|
height: 180px;
|
||||||
|
width: 100%;
|
||||||
|
border-width: 1px 1px 0 0;
|
||||||
|
|
||||||
|
&:nth-child(2n) {
|
||||||
|
border-right-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-learningLevel {
|
||||||
|
font: 400 54px/64px Helvetica, Arial, sans-serif;
|
||||||
|
height: var(--absElemOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-name {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-subTitle {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-progress {
|
||||||
|
height: var(--absElemOffset);
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
height: 90px;
|
||||||
|
padding: 10px;
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.tile-learningLevel {
|
||||||
|
line-height: 90px;
|
||||||
|
font-size: 36px;
|
||||||
|
width: 58px;
|
||||||
|
height: 90px;
|
||||||
|
margin: 0 0 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-name {
|
||||||
|
position: relative;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 19px;
|
||||||
|
font-weight: 400;
|
||||||
|
margin: 0 25px 3px 64px;
|
||||||
|
width: calc(100% - 89px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-subTitle {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 19px;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 0 25px 0 64px;
|
||||||
|
width: calc(100% - 89px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile-progress {
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
56
sources-gen/components/Dashboard/Tiles/Tiles.jsx
Normal file
56
sources-gen/components/Dashboard/Tiles/Tiles.jsx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { Fragment } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { colors, resolutions } from '../../../utils/css';
|
||||||
|
import { StyledTile as Tile } from './Tile/Tile';
|
||||||
|
import { StyledBlankTile as BlankTile } from './Tile/BlankTile';
|
||||||
|
import { StyledMoreCoursesTile as MoreCoursesTile } from './Tile/MoreCoursesTile';
|
||||||
|
import { tileColors } from '../../../constants/tileColors';
|
||||||
|
import { uniqueId } from '../../../utils/htmlUtils';
|
||||||
|
|
||||||
|
export const Tiles = ({ className, data }) => {
|
||||||
|
return (
|
||||||
|
<nav className={className}>
|
||||||
|
{data.map((tileData, index) => {
|
||||||
|
const tileElement = (
|
||||||
|
<Tile
|
||||||
|
key={tileData.id}
|
||||||
|
backgroundColor={tileColors[index % tileColors.length]}
|
||||||
|
data={tileData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
// check if the number of the fetched tiles is even and if it is,
|
||||||
|
// then add a blank tile as penultimate
|
||||||
|
return data.length % 2 === 0 && data.indexOf(tileData) === data.length - 1 ? (
|
||||||
|
<Fragment key={uniqueId()}>
|
||||||
|
{tileElement}
|
||||||
|
<BlankTile />
|
||||||
|
</Fragment>
|
||||||
|
) : (
|
||||||
|
tileElement
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<MoreCoursesTile backgroundColor={colors.LG_BLUE_5} />
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StyledTiles = styled(Tiles)`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
width: 100%;
|
||||||
|
min-height: 500px;
|
||||||
|
border-bottom: 1px solid ${colors.LG_WHITE};
|
||||||
|
|
||||||
|
@media (min-width: ${resolutions.min.desktop}px) {
|
||||||
|
width: 1200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
36
sources-gen/components/DwPicture/DwPicture.jsx
Normal file
36
sources-gen/components/DwPicture/DwPicture.jsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { useFrontendConfig } from '../../hooks/useFrontendConfig';
|
||||||
|
import { imgWithFormatFn, format } from '../../utils/imgUtils';
|
||||||
|
import { resolutions } from '../../utils/css';
|
||||||
|
import { Picture } from '../Picture/Picture';
|
||||||
|
|
||||||
|
export const DwPicture = ({ imageId, ...inProps }) => {
|
||||||
|
const { imageBasePath } = useFrontendConfig();
|
||||||
|
|
||||||
|
const imgWithFormat = imgWithFormatFn(imageId, imageBasePath);
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
fallbackUrl: imgWithFormat(format.full),
|
||||||
|
sources: [
|
||||||
|
{
|
||||||
|
media: `(min-width: ${resolutions.min.full}px)`,
|
||||||
|
srcSet: imgWithFormat(format.full),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
media: `(min-width: ${resolutions.min.tabletLandscape}px)`,
|
||||||
|
srcSet: imgWithFormat(format.lg),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
media: `(min-width: ${resolutions.min.tablet}px)`,
|
||||||
|
srcSet: imgWithFormat(format.md),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
media: `(min-width: ${resolutions.min.mobile}px)`,
|
||||||
|
srcSet: imgWithFormat(format.sm),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = { ...defaultProps, ...inProps };
|
||||||
|
|
||||||
|
return <Picture {...props} />;
|
||||||
|
};
|
168
sources-gen/components/Footer/Footer.jsx
Normal file
168
sources-gen/components/Footer/Footer.jsx
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import gql from 'graphql-tag';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { colors, resolutions } from '../../utils/css';
|
||||||
|
import { I18nText } from '../I18n/I18nText';
|
||||||
|
import {
|
||||||
|
getDwContactUrl,
|
||||||
|
getDwUrlWithLang,
|
||||||
|
getFooterLinkForNamedUrl,
|
||||||
|
getLegalUrl,
|
||||||
|
} from '../../utils/url/urlFactory';
|
||||||
|
import { useRtlContext } from '../../hooks/useRtl';
|
||||||
|
import { legalFragment } from '../LegalNotice/LegalNotice';
|
||||||
|
|
||||||
|
export const footerFragment = {
|
||||||
|
name: 'Footer',
|
||||||
|
fragment() {
|
||||||
|
return gql`fragment ${this.name} on Query {
|
||||||
|
footer(lang: $lang) {
|
||||||
|
accessibility(appName: "mdl") {
|
||||||
|
namedUrl
|
||||||
|
}
|
||||||
|
policy(appName: "mdl") {
|
||||||
|
namedUrl
|
||||||
|
}
|
||||||
|
${legalFragment.partial()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Footer = ({ className, data }) => {
|
||||||
|
const { isRtl } = useRtlContext();
|
||||||
|
const { langCode } = useParams();
|
||||||
|
|
||||||
|
const rtlClass = isRtl ? 'rtl' : '';
|
||||||
|
return (
|
||||||
|
<footer className={`${className} ${rtlClass}`} aria-label="Main Footer">
|
||||||
|
<ul className={rtlClass}>
|
||||||
|
{footerData({ langCode, data }).map(footerObject => (
|
||||||
|
<li key={footerObject.id} className={rtlClass}>
|
||||||
|
<I18nText
|
||||||
|
isA="a"
|
||||||
|
className="footer-link"
|
||||||
|
translation={footerObject.translation}
|
||||||
|
href={footerObject.href}
|
||||||
|
target={footerObject.target}
|
||||||
|
role={footerObject.role}
|
||||||
|
aria-label={footerObject.aria}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const footerData = ({ langCode, data }) => [
|
||||||
|
{
|
||||||
|
translation: {
|
||||||
|
key: 'footer.copyright',
|
||||||
|
parameters: { first: new Date().getFullYear() },
|
||||||
|
},
|
||||||
|
id: 0,
|
||||||
|
aria: 'footer.copyright',
|
||||||
|
role: 'Firm name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translation: 'footer.dw',
|
||||||
|
id: 1,
|
||||||
|
href: getDwUrlWithLang({ langCode }),
|
||||||
|
target: '_blank',
|
||||||
|
aria: 'footer.dw',
|
||||||
|
role: 'link',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translation: 'footer.privacyPolicy',
|
||||||
|
id: 2,
|
||||||
|
href: getFooterLinkForNamedUrl({ namedUrl: data.footer.policy.namedUrl }),
|
||||||
|
target: '_blank',
|
||||||
|
aria: 'footer.privacyPolicy',
|
||||||
|
role: 'link',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translation: 'footer.accessibility',
|
||||||
|
id: 3,
|
||||||
|
href: getFooterLinkForNamedUrl({ namedUrl: data.footer.accessibility.namedUrl }),
|
||||||
|
target: '_blank',
|
||||||
|
aria: 'footer.accessibility',
|
||||||
|
role: 'link',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translation: 'footer.legal',
|
||||||
|
id: 4,
|
||||||
|
href: getLegalUrl(langCode),
|
||||||
|
target: '',
|
||||||
|
aria: 'footer.legal',
|
||||||
|
role: 'link',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translation: 'footer.contact',
|
||||||
|
id: 5,
|
||||||
|
href: getDwContactUrl(),
|
||||||
|
target: '_blank',
|
||||||
|
aria: 'footer.contact',
|
||||||
|
role: 'link',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const StyledFooter = styled(Footer)`
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 90px;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 45px;
|
||||||
|
margin: 20px 0;
|
||||||
|
background: ${colors.LG_BLUE_7};
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
max-width: 100%;
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-right: 12px;
|
||||||
|
padding: 0 0 0 12px;
|
||||||
|
|
||||||
|
&.rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link {
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 15px;
|
||||||
|
color: ${colors.LG_BLUE_4};
|
||||||
|
background-color: transparent;
|
||||||
|
:hover,
|
||||||
|
:active,
|
||||||
|
:focus {
|
||||||
|
color: ${colors.LG_WHITE};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.tablet}px) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${resolutions.max.mobile}px) {
|
||||||
|
max-width: 100%;
|
||||||
|
min-height: 65px;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
5
sources-gen/components/GdprLayer/BrowserOnly.jsx
Normal file
5
sources-gen/components/GdprLayer/BrowserOnly.jsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { isServer } from '../../utils/ssr';
|
||||||
|
|
||||||
|
export const BrowserOnly = ({ children, ...restProps }) => (
|
||||||
|
<div {...restProps}>{!isServer() && children}</div>
|
||||||
|
);
|
44
sources-gen/components/GdprLayer/GdprLayer.jsx
Normal file
44
sources-gen/components/GdprLayer/GdprLayer.jsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import config from '../../config';
|
||||||
|
import { userSelector } from '../../state/user/userSelectors';
|
||||||
|
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
||||||
|
import { I18nText } from '../I18n/I18nText';
|
||||||
|
import { BrowserOnly } from './BrowserOnly';
|
||||||
|
|
||||||
|
export const GdprLayer = ({ footerData }) => {
|
||||||
|
const { isLoggedIn } = useSelector(userSelector);
|
||||||
|
const [hasAcceptedGdpr, setHasAcceptedGdpr] = useLocalStorage('hasAcceptedGdpr');
|
||||||
|
const { namedUrl } = footerData.footer.policy || {};
|
||||||
|
|
||||||
|
if (isLoggedIn || hasAcceptedGdpr) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BrowserOnly>
|
||||||
|
<div className="cookie" style={{ left: 0 }}>
|
||||||
|
<div className="cookie__wrap">
|
||||||
|
<div className="cookie__item">
|
||||||
|
<I18nText isA="p" className="cookie__text" translation="common.gdpr.overlay.text" />
|
||||||
|
</div>
|
||||||
|
<div className="cookie__buttons">
|
||||||
|
<I18nText
|
||||||
|
isA="a"
|
||||||
|
translation="common.gdpr.overlay.moreButton"
|
||||||
|
className="cookie__btn cookie__btn--more"
|
||||||
|
href={`${config.dw.baseUrl}${namedUrl}`}
|
||||||
|
target="_blank"
|
||||||
|
/>
|
||||||
|
<I18nText
|
||||||
|
isA="a"
|
||||||
|
translation="common.gdpr.overlay.okButton"
|
||||||
|
className="cookie__btn cookie__btn--ok"
|
||||||
|
href="#"
|
||||||
|
onClick={() => setHasAcceptedGdpr(true)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BrowserOnly>
|
||||||
|
);
|
||||||
|
};
|
40
sources-gen/components/GoogleTagManager/GtmDataLayer.jsx
Normal file
40
sources-gen/components/GoogleTagManager/GtmDataLayer.jsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
import { GtmNoScriptFallback } from './GtmNoScriptFallback';
|
||||||
|
import { useStaticInfoForGtm } from './hooks/useStaticInfoForGtm';
|
||||||
|
import { gtmDataLayerPartial, TrackingUtils } from './TrackingUtils';
|
||||||
|
import { useCourseData } from '../../hooks/useCourseData';
|
||||||
|
|
||||||
|
export const gtmDataLayerFragment = gtmDataLayerPartial;
|
||||||
|
|
||||||
|
export const GtmDataLayer = ({ content, noContentPageId, push = false }) => {
|
||||||
|
const { gtmLevel1Id: level1Id, macaParam, pageUrl } = useStaticInfoForGtm();
|
||||||
|
const { courseId } = useCourseData();
|
||||||
|
|
||||||
|
const dataLayer = TrackingUtils.generateDataLayer({
|
||||||
|
content,
|
||||||
|
macaParam,
|
||||||
|
level1Id,
|
||||||
|
pageUrl,
|
||||||
|
courseId,
|
||||||
|
noContentPageId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (push) {
|
||||||
|
TrackingUtils.pushToGoogleTagManager({
|
||||||
|
withReset: true,
|
||||||
|
datalayerObj: {
|
||||||
|
event: 'onPageChange',
|
||||||
|
...dataLayer,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<script>{TrackingUtils.initDataLayerScript(dataLayer)}</script>
|
||||||
|
</Helmet>
|
||||||
|
<GtmNoScriptFallback dataLayer={dataLayer} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
13
sources-gen/components/GoogleTagManager/GtmLoadScript.jsx
Normal file
13
sources-gen/components/GoogleTagManager/GtmLoadScript.jsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
import { useFrontendConfig } from '../../hooks/useFrontendConfig';
|
||||||
|
|
||||||
|
export const GtmLoadScript = () => (
|
||||||
|
<Helmet>
|
||||||
|
<script>
|
||||||
|
{`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||||
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||||
|
})(window,document,'script','dataLayer','GTM-${useFrontendConfig().gtmId}');`}
|
||||||
|
</script>
|
||||||
|
</Helmet>
|
||||||
|
);
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { objectToQueryParams } from '../../utils/url/url';
|
||||||
|
import { useFrontendConfig } from '../../hooks/useFrontendConfig';
|
||||||
|
|
||||||
|
export const GtmNoScriptFallback = ({ dataLayer }) => {
|
||||||
|
const hideIframeStyles = {
|
||||||
|
display: 'none',
|
||||||
|
visibility: 'hidden',
|
||||||
|
};
|
||||||
|
const { gtmId } = useFrontendConfig();
|
||||||
|
return (
|
||||||
|
<noscript>
|
||||||
|
<iframe
|
||||||
|
title={`GTM-${gtmId}`}
|
||||||
|
src={`https://www.googletagmanager.com/ns.html?id=GTM-${gtmId}&${objectToQueryParams(
|
||||||
|
dataLayer,
|
||||||
|
)}`}
|
||||||
|
height="0"
|
||||||
|
width="0"
|
||||||
|
style={hideIframeStyles}
|
||||||
|
/>
|
||||||
|
</noscript>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { isServer } from '../../utils/ssr';
|
||||||
|
import globals from '../../utils/globals';
|
||||||
|
|
||||||
|
import { GtmLoadScript } from './GtmLoadScript';
|
||||||
|
import { GtmDataLayer } from './GtmDataLayer';
|
||||||
|
|
||||||
|
export { gtmDataLayerFragment } from './GtmDataLayer';
|
||||||
|
|
||||||
|
export const GtmScriptWithDataLayer = ({ content = {}, noContentPageId }) => {
|
||||||
|
const isGtmAlreadyInitialized = !isServer() && !!globals.window.dataLayer;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<GtmDataLayer
|
||||||
|
content={content}
|
||||||
|
noContentPageId={noContentPageId}
|
||||||
|
push={isGtmAlreadyInitialized}
|
||||||
|
/>
|
||||||
|
{!isGtmAlreadyInitialized && <GtmLoadScript />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
139
sources-gen/components/GoogleTagManager/TrackingUtils.jsx
Normal file
139
sources-gen/components/GoogleTagManager/TrackingUtils.jsx
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
import gql from 'graphql-tag';
|
||||||
|
import globals from '../../utils/globals';
|
||||||
|
|
||||||
|
const isValidList = list => list?.length > 0;
|
||||||
|
|
||||||
|
const addCurrentNavToRootList = ({ nav }) => [...nav.navsToRoot, nav];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
const contentTitle = content => (content.__typename === 'Person' ? content.fullName : content.name);
|
||||||
|
|
||||||
|
const pickCategoryName = ({ navs, index }) => (navs[index] || {}).name;
|
||||||
|
|
||||||
|
export const gtmDataLayerPartial = {
|
||||||
|
name: 'GtmDataLayer',
|
||||||
|
partial() {
|
||||||
|
return `
|
||||||
|
...on ModelAspect {
|
||||||
|
id
|
||||||
|
gtmLanguageCode
|
||||||
|
gtmContentType
|
||||||
|
}
|
||||||
|
...on DeliveryAspect {
|
||||||
|
gtmContentDate
|
||||||
|
}
|
||||||
|
...on NamedAspect {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
...on AssociationsAspect {
|
||||||
|
navigations {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
navsToRoot {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subjects {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
topics:categories {
|
||||||
|
originId
|
||||||
|
}
|
||||||
|
departments {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mediaInfoForTrackingFragment = {
|
||||||
|
name: 'MediaInfoForTrackingFragment',
|
||||||
|
fragment({ type }) {
|
||||||
|
return gql`fragment ${this.name} on ${type} {
|
||||||
|
videos {
|
||||||
|
${gtmDataLayerPartial.partial()}
|
||||||
|
}
|
||||||
|
audios {
|
||||||
|
${gtmDataLayerPartial.partial()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateContentGtmInfo = ({
|
||||||
|
content,
|
||||||
|
level1Id,
|
||||||
|
macaParam,
|
||||||
|
pageUrl,
|
||||||
|
courseId,
|
||||||
|
noContentPageId,
|
||||||
|
}) => {
|
||||||
|
const navs = isValidList(content.navigations) ? content.navigations : [{ navsToRoot: [] }];
|
||||||
|
const alignedNavs = addCurrentNavToRootList({ nav: navs[0] });
|
||||||
|
|
||||||
|
return {
|
||||||
|
categoryLevel1: pickCategoryName({ navs: alignedNavs, index: 0 }),
|
||||||
|
categoryLevel2: pickCategoryName({ navs: alignedNavs, index: 1 }),
|
||||||
|
categoryLevel3: pickCategoryName({ navs: alignedNavs, index: 2 }),
|
||||||
|
contentTitle: contentTitle(content),
|
||||||
|
contentLanguage: content.gtmLanguageCode,
|
||||||
|
pageOID: content.id,
|
||||||
|
contentType: content.gtmContentType,
|
||||||
|
date: content.gtmContentDate,
|
||||||
|
subject: content.subjects ? content.subjects[0]?.name : {},
|
||||||
|
topicIds: content.topics?.map(topic => topic.originId),
|
||||||
|
pageSID: navs[0].id,
|
||||||
|
departmentName: content.departments ? content.departments[0]?.name : {},
|
||||||
|
categoryType: 1,
|
||||||
|
displayForm: 5,
|
||||||
|
level1ID: level1Id,
|
||||||
|
macaParam,
|
||||||
|
pageUrl,
|
||||||
|
courseId,
|
||||||
|
noContentPageId,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TrackingUtils = {
|
||||||
|
initDataLayerScript: datalayer => {
|
||||||
|
const initialDataLayer = {
|
||||||
|
...datalayer,
|
||||||
|
event: 'onPageChange',
|
||||||
|
};
|
||||||
|
|
||||||
|
return `
|
||||||
|
if(!window.dataLayer) {
|
||||||
|
window.dataLayer = [${JSON.stringify(initialDataLayer)}]
|
||||||
|
};`.trim();
|
||||||
|
},
|
||||||
|
generateDataLayer: ({ content, level1Id, macaParam, pageUrl, courseId, noContentPageId }) => ({
|
||||||
|
pageData: {
|
||||||
|
...generateContentGtmInfo({
|
||||||
|
content,
|
||||||
|
level1Id,
|
||||||
|
macaParam,
|
||||||
|
pageUrl,
|
||||||
|
courseId,
|
||||||
|
noContentPageId,
|
||||||
|
}),
|
||||||
|
embeddings: {},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
pushToGoogleTagManager: ({ datalayerObj, withReset = false }) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (withReset) {
|
||||||
|
TrackingUtils.resetDataLayer();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line fp/no-mutating-methods
|
||||||
|
globals.window.dataLayer?.push(datalayerObj);
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
resetDataLayer: () => {
|
||||||
|
// eslint-disable-next-line fp/no-mutating-methods
|
||||||
|
globals.window.dataLayer.push(function dontUseArrowFunction() {
|
||||||
|
this.reset();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { TrackingUtils } from '../TrackingUtils';
|
||||||
|
|
||||||
|
const eventName = 'addEmbeddings';
|
||||||
|
|
||||||
|
export const useAddEmbeddingsToGtm = ({ dictionary }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
TrackingUtils.pushToGoogleTagManager({
|
||||||
|
datalayerObj: {
|
||||||
|
event: eventName,
|
||||||
|
pageData: {
|
||||||
|
embeddings: dictionary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
};
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { useStaticInfoForGtm } from './useStaticInfoForGtm';
|
||||||
|
import { generateContentGtmInfo } from '../TrackingUtils';
|
||||||
|
import { useAddEmbeddingsToGtm } from './useAddEmbeddingsToGtm';
|
||||||
|
|
||||||
|
export const useMediaTracking = content => {
|
||||||
|
const { level1Id, macaParam, pageUrl } = useStaticInfoForGtm();
|
||||||
|
const contentDictionary = {
|
||||||
|
[content.id]: generateContentGtmInfo({
|
||||||
|
content,
|
||||||
|
level1Id,
|
||||||
|
macaParam,
|
||||||
|
pageUrl,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
useAddEmbeddingsToGtm({ dictionary: contentDictionary });
|
||||||
|
};
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { useStaticInfoForGtm } from './useStaticInfoForGtm';
|
||||||
|
import { generateContentGtmInfo } from '../TrackingUtils';
|
||||||
|
import { useAddEmbeddingsToGtm } from './useAddEmbeddingsToGtm';
|
||||||
|
|
||||||
|
export const useMediaTracking = content => {
|
||||||
|
const { level1Id, macaParam, pageUrl } = useStaticInfoForGtm();
|
||||||
|
const contentDictionary = {
|
||||||
|
[content.id]: generateContentGtmInfo({
|
||||||
|
content,
|
||||||
|
level1Id,
|
||||||
|
macaParam,
|
||||||
|
pageUrl,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
useAddEmbeddingsToGtm({ dictionary: contentDictionary });
|
||||||
|
};
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { useGlobalsContext } from '../../../context/GlobalsContext';
|
||||||
|
import { useLocationQueryParam } from '../../../hooks/useLocationQueryParam';
|
||||||
|
import { useFrontendConfig } from '../../../hooks/useFrontendConfig';
|
||||||
|
|
||||||
|
export const useStaticInfoForGtm = () => {
|
||||||
|
const pageUrl = useGlobalsContext().window.location.href.split('?')[0];
|
||||||
|
const macaParam = useLocationQueryParam('maca');
|
||||||
|
const { gtmLevel1Id } = useFrontendConfig();
|
||||||
|
|
||||||
|
return { gtmLevel1Id, macaParam, pageUrl };
|
||||||
|
};
|
6
sources-gen/components/GoogleTagManager/index.jsx
Normal file
6
sources-gen/components/GoogleTagManager/index.jsx
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { GtmScriptWithDataLayer as NotMemoGtmScriptWithDataLayer } from './GtmScriptWithDataLayer';
|
||||||
|
|
||||||
|
export { gtmDataLayerFragment } from './GtmScriptWithDataLayer';
|
||||||
|
|
||||||
|
export const GtmScriptWithDataLayer = memo(NotMemoGtmScriptWithDataLayer);
|
30
sources-gen/components/GrammarItem/GrammarItem.jsx
Normal file
30
sources-gen/components/GrammarItem/GrammarItem.jsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { wrapTablesWithDiv } from '../../utils/replacers/htmlReplacer';
|
||||||
|
import { useKnowledgePlaceholderReplacementEffect } from '../Modal/KnowledgeModal/useKnowledgePlaceholderReplacementEffect';
|
||||||
|
import { WithRenderDelay } from '../WithRenderDelay/WithRenderDelay';
|
||||||
|
import { replacePlaceholderImagesWithResponsivePictures } from '../../utils/replacers/imageReplacer';
|
||||||
|
import { RichText } from '../RichText/RichText';
|
||||||
|
import { ContentHeadline } from '../ContentContainer/ContentHeadline/ContentHeadline';
|
||||||
|
|
||||||
|
export const GrammarItem = ({ data }) => {
|
||||||
|
const { name, text, knowledges } = data.content;
|
||||||
|
const markup = wrapTablesWithDiv(text);
|
||||||
|
|
||||||
|
useKnowledgePlaceholderReplacementEffect({ knowledges });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="section exercise-container vocabulary copy">
|
||||||
|
<ContentHeadline>
|
||||||
|
<h2 dir="auto">{name}</h2>
|
||||||
|
</ContentHeadline>
|
||||||
|
<div className="row vocabulary">
|
||||||
|
<div className="col-sm-offset-1 col-sm-10 col-lg-offset-2 col-lg-8">
|
||||||
|
<WithRenderDelay
|
||||||
|
actionToBeDelayed={replacePlaceholderImagesWithResponsivePictures}
|
||||||
|
delayTime={10}
|
||||||
|
render={() => <RichText content={markup} />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue