diff --git a/package.json b/package.json index 3bcfe15d8..92de37681 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "react-markdown-loader": "^1.1.14", "react-modal": "^3.4.4", "react-popover": "^0.5.7", - "react-redux": "^6.0.1", + "react-redux": "^7.2.0", "react-responsive": "^6.1.1", "react-style-proptype": "^3.2.1", "react-tabs": "^3.0.0", @@ -129,9 +129,9 @@ "rimraf": "^2.6.1", "scratch-paint": "0.2.0-prerelease.20181120191526", "scratch-render": "0.1.0-prerelease.20210325231800", + "scratch-render-fonts": "1.0.0-prerelease.20210401210003", "scratch-storage": "1.2.2", "scratch-svg-renderer": "0.2.0-prerelease.20210511195415", - "scratch-render-fonts": "1.0.0-prerelease.20210401210003", "selenium-webdriver": "4.0.0-alpha.1", "serverless": "^1.30.3", "serverless-domain-manager": "^3.1.0", diff --git a/src/components/menu/menu.jsx b/src/components/menu/menu.jsx index 6aaf13f27..ed51ae12c 100644 --- a/src/components/menu/menu.jsx +++ b/src/components/menu/menu.jsx @@ -9,7 +9,6 @@ import { Link } from 'redux-little-router' import InlineSVG from '../inline-svg/inline-svg.jsx' import MenuButton from '../menu-button/menu-button.jsx' import MenuListing, { SHAPE_PROJECT } from '../menu-listing/menu-listing.jsx' -import OfflineSupport from '../offline-support/offline-support.jsx' import wdrLogo from '../../../assets/img/wdr_logo.svg' import headLogo from '../../../assets/img/head_logo.png' @@ -39,6 +38,13 @@ export const MenuComponent = (props) => { tabSelected: classNames(tabStyles.reactTabsTabSelected, styles.isSelected), } + const offlineOption = () => { + const buttonText = useFeatureFlag(FEATURE_OFFLINE) ? 'Offlineversion aktiviert' : 'Offlinemodus aktivieren' + return ( + {buttonText} + ) + } + return (
@@ -62,7 +68,7 @@ export const MenuComponent = (props) => { Ⓒ WDR {new Date().getFullYear()} - {useFeatureFlag(FEATURE_OFFLINE) && } + {offlineOption()}
diff --git a/src/components/offline-support/offline-support.css b/src/components/offline-support/offline-support.css new file mode 100644 index 000000000..d0ae5c72d --- /dev/null +++ b/src/components/offline-support/offline-support.css @@ -0,0 +1,9 @@ +@import '../../css/colors.css'; + + +.link { + text-decoration: underline; + padding: 0; + color: $ui-wdr-blue; + font-weight: 600; +} diff --git a/src/components/offline-support/offline-support.jsx b/src/components/offline-support/offline-support.jsx index 9a79bf838..3d9fe1335 100644 --- a/src/components/offline-support/offline-support.jsx +++ b/src/components/offline-support/offline-support.jsx @@ -4,9 +4,25 @@ import PropTypes from 'prop-types' import { connect } from 'react-redux' import ButtonComponent from '../button/button.jsx' import { setEnabled } from '../../reducers/offline.js' +import styles from '../../css/offline.css' + + +// TODO: add changing local storage key value before setEnabled const OfflineSupport = (props) => { const offlineSupport = 'serviceWorker' in navigator + + const toggleButton = (enabled) => ( + props.setEnabled(!enabled)} + > + {`Offlinemodus ${enabled ? 'Deaktivieren' : 'Aktivieren'}`} + + ) + + if (!offlineSupport) { return null } @@ -16,19 +32,27 @@ const OfflineSupport = (props) => { } if (props.installed) { - return
Offlineversion aktiviert
+ return ( + <> + {toggleButton(true)} +
Offlineversion aktiviert
+ + ) } if (!props.enabled) { return ( - props.setEnabled(true)}> - Offlinemodus aktivieren - + toggleButton(false) ) } if (props.installError !== null) { - return
Fehler: {props.installError}
+ return ( + <> + {toggleButton(true)} + Fehler: {props.installError} + + ) } return null diff --git a/src/containers/app.jsx b/src/containers/app.jsx index b9131fe4c..815573b2a 100644 --- a/src/containers/app.jsx +++ b/src/containers/app.jsx @@ -31,6 +31,7 @@ import Menu from './menu.jsx' import WelcomeScreen from './welcome-screen.jsx' import LazyRender from './lazy-render.jsx' import Content from './content.jsx' +import OfflineModus from './offline-modus.jsx' import MobileScreenFallback from './mobile-screen-fallback.jsx' addLocaleData(de) @@ -174,6 +175,8 @@ class App extends Component { return case Views.content: return + case Views.offline: + return case Views.welcome: return case Views.menu: diff --git a/src/containers/offline-modus.jsx b/src/containers/offline-modus.jsx new file mode 100644 index 000000000..3d2864dff --- /dev/null +++ b/src/containers/offline-modus.jsx @@ -0,0 +1,94 @@ +import React, { useEffect } from 'react' + +import betaLogo from '../../assets/img/beta_header_sans.png' +import styles from '../css/offline.css' + +import '../css/defaults.css' +import ButtonComponent from '../components/button/button.jsx' +import { useState } from 'react' +import { localStorageKey } from '../lib/feature-flags' +import { FEATURE_OFFLINE } from '../lib/feature-flags' +import { useCallback } from 'react' +import Modal from './modal.jsx' +import { setEnabled } from '../reducers/offline' +import OfflineSupport from '../components/offline-support/offline-support.jsx' +import { useDispatch, useSelector } from 'react-redux' + +const OfflineModus = () => { + const dispatch = useDispatch() + const offlineState = useSelector((state) => state.scratchGui.offline) + const modusKey = localStorageKey(FEATURE_OFFLINE) + const initState = Boolean(localStorage.getItem(modusKey)) + const [modusActivated, setModusActivated] = useState(initState) + + const toggleOfflineModus = useCallback(() => { + modusActivated ? localStorage.removeItem(modusKey) : localStorage.setItem(modusKey, 'true') + setModusActivated((prevState) => !prevState) + }, [setModusActivated] + ) + + // TODO: implement this in offline-support component + + const activateButton = ( + + Offlinemodus aktivieren + + ) + + useEffect(() => { + console.log("state chaged", offlineState) + + // if (!offlineState.enabled) { + // localStorage.removeItem(modusKey) + // } else { + // localStorage.setItem(modusKey, 'true') + // } + + }, [offlineState]) + + return ( + window.location.assign('/')} + id="offline-modus-modal" + > +
+
+ + +

+ Programmieren mit der Maus ohne Internetverbindung nutzen -
nur im Chrome Browser +

+ +

+ Um Schulen zu unterstützen, die nicht überall oder nicht durchgehend gutes Internet haben, + stellen wir für Programmieren mit der Maus eine Offline-Version zur Verfügung. +

+ +

+ So geht’s:
+ An einem Ort mit Internet an jedem Gerät einmal auf “Offlinemodus aktivieren” klicken. + Alle erfoderlichen Inhalte werden dann heruntergeladen. Wenn das erfolgreich war, erscheint + “Offlinemodus aktiviert”.
+ Programmieren mit der Maus kann dann ohne Internetverbindung verwendet werden. Von den Kindern + angelegte Projekte werden auf dem Gerät gespeichert, bis wieder eine Internetverbindung besteht. +

+ + + Die Funktion ist noch in der Entwicklung. Derzeit funktioniert der Offlinemodus + nur im Chrome-Browser. + + + +
+
+
+ ) +} + +export default OfflineModus diff --git a/src/css/offline.css b/src/css/offline.css new file mode 100644 index 000000000..d3a0412bf --- /dev/null +++ b/src/css/offline.css @@ -0,0 +1,33 @@ +.background { + background-image: url(../components/menu/bg_blue@1x.png); + display: flex; + align-items: center; + justify-content: center; + height: 100%; +} + +.wrapper { + background-color: white; + padding: 3rem; + max-width: 80vw; + box-shadow: 0 0 0.8rem 1px rgba(0, 0, 0, 0.5); +} + +.logo { + display: block; + width: 100%; + max-width: 400px; + margin: 0 auto 2rem auto; +} + +h1 { + text-align: center; + margin: 3rem 0; +} + +.feature-button { + width: 15rem; + margin: 2rem auto 1rem; + justify-content: center; + padding: 0.75rem; +} diff --git a/src/lib/routing.js b/src/lib/routing.js index 9201c61ba..b325dbe8c 100644 --- a/src/lib/routing.js +++ b/src/lib/routing.js @@ -5,6 +5,7 @@ export const Views = { menu: 'VIEW_MENU', project: 'VIEW_PROJECT', content: 'content', + offline: 'offline', welcome: 'welcome', } @@ -56,6 +57,9 @@ const routes = { '/:page': { view: Views.content, }, + '/offline': { + view: Views.offline, + }, } export const { reducer, middleware, enhancer } = routerForBrowser({ routes }) diff --git a/yarn.lock b/yarn.lock index dff317dea..1b1834df3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13071,11 +13071,16 @@ react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== -react-is@^16.8.2, react-is@^16.8.4: +react-is@^16.8.4: version "16.8.4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== +react-is@^16.9.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -13132,17 +13137,16 @@ react-popper@^1.3.3: typed-styles "^0.0.7" warning "^4.0.2" -react-redux@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-6.0.1.tgz#0d423e2c1cb10ada87293d47e7de7c329623ba4d" - integrity sha512-T52I52Kxhbqy/6TEfBv85rQSDz6+Y28V/pf52vDWs1YRXG19mcFOGfHnY2HsNFHyhP+ST34Aih98fvt6tqwVcQ== +react-redux@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d" + integrity sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA== dependencies: - "@babel/runtime" "^7.3.1" + "@babel/runtime" "^7.5.5" hoist-non-react-statics "^3.3.0" - invariant "^2.2.4" loose-envify "^1.4.0" prop-types "^15.7.2" - react-is "^16.8.2" + react-is "^16.9.0" react-responsive@^6.1.1: version "6.1.1"