+
-
+
diff --git a/locale.json b/locale.json
index af87235ce..cce172efa 100644
--- a/locale.json
+++ b/locale.json
@@ -5,6 +5,7 @@
"slogan": "A free online course",
"description": "spaCy is a modern Python library for industrial-strength Natural Language Processing. In this free and interactive online course, you'll learn how to use spaCy to build advanced natural language understanding systems, using both rule-based and machine learning approaches.",
"bio": "I'm Ines, one of the core developers of spaCy and the co-founder of Explosion. I specialize in modern developer tools for AI, Machine Learning and NLP. I also really love building stuff for the web.",
+ "video": "THduWAnG97k",
"footerLinks": [
{
"text": "spaCy Website",
@@ -40,7 +41,10 @@
"launchingDocker": "Launching Docker container on",
"reconnectingDocker": "Reconnecting to Docker container on",
"prevChapter": "Previous Chapter",
- "nextChapter": "Next Chapter"
+ "nextChapter": "Next Chapter",
+ "start": "Start",
+ "video": "Video",
+ "slides": "Slides"
}
},
"de": {
@@ -84,7 +88,10 @@
"launchingDocker": "Starte Docker-Container auf",
"reconnectingDocker": "Verbinde mit Docker-Container auf",
"prevChapter": "Vorheriges Kapitel",
- "nextChapter": "Nächstes Kapitel"
+ "nextChapter": "Nächstes Kapitel",
+ "start": "Start",
+ "video": "Video",
+ "slides": "Präsentation"
}
},
"es": {
diff --git a/package-lock.json b/package-lock.json
index 6c3893c3a..2ee5e7d9c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4113,6 +4113,11 @@
"array-find-index": "^1.0.1"
}
},
+ "custom-event-polyfill": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz",
+ "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w=="
+ },
"cwebp-bin": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cwebp-bin/-/cwebp-bin-5.0.0.tgz",
@@ -9391,6 +9396,11 @@
}
}
},
+ "loadjs": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz",
+ "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA=="
+ },
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@@ -11200,6 +11210,25 @@
}
}
},
+ "plyr": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/plyr/-/plyr-3.6.2.tgz",
+ "integrity": "sha512-CjAhRDtzyGqMRte9Phj4FsZFegS9VxW60boOhQsAnZHuiFG3yVBRcodWsGZ79GuXHHelc4DxMHO+z0QggY+9qQ==",
+ "requires": {
+ "core-js": "^3.6.5",
+ "custom-event-polyfill": "^1.0.7",
+ "loadjs": "^4.2.0",
+ "rangetouch": "^2.0.1",
+ "url-polyfill": "^1.1.8"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
+ "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
+ }
+ }
+ },
"pngjs": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
@@ -12120,6 +12149,11 @@
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
+ "rangetouch": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz",
+ "integrity": "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA=="
+ },
"raw-body": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
@@ -15316,6 +15350,11 @@
"prepend-http": "^1.0.1"
}
},
+ "url-polyfill": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.8.tgz",
+ "integrity": "sha512-Ey61F4FEqhcu1vHSOMmjl0Vd/RPRLEjMj402qszD/dhMBrVfoUsnIj8KSZo2yj+eIlxJGKFdnm6ES+7UzMgZ3Q=="
+ },
"url-regex": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz",
diff --git a/package.json b/package.json
index 22372c6fa..97c1af959 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"gatsby-transformer-sharp": "^2.1.17",
"juniper-js": "^0.1.0",
"node-sass": "^4.11.0",
+ "plyr": "^3.6.2",
"prismjs": "^1.15.0",
"react": "^16.8.2",
"react-dom": "^16.8.2",
diff --git a/src/components/button.js b/src/components/button.js
index 441f131bb..10c308474 100644
--- a/src/components/button.js
+++ b/src/components/button.js
@@ -1,7 +1,7 @@
import React, { useContext } from 'react'
import classNames from 'classnames'
-import { UiTextContext } from '../context'
+import { LocaleContext } from '../context'
import IconCheck from '../../static/icon_check.svg'
import classes from '../styles/button.module.sass'
@@ -19,7 +19,7 @@ export const Button = ({ Component = 'button', children, onClick, variant, small
}
export const CompleteButton = ({ completed, toggleComplete, small = true }) => {
- const uiText = useContext(UiTextContext)
+ const { uiText } = useContext(LocaleContext)
const buttonClassNames = classNames({
[classes.completeInactive]: !completed,
[classes.completeActive]: completed,
diff --git a/src/components/choice.js b/src/components/choice.js
index 4be943db6..de06a860c 100644
--- a/src/components/choice.js
+++ b/src/components/choice.js
@@ -2,11 +2,11 @@ import React, { useState, useCallback, useContext } from 'react'
import classNames from 'classnames'
import { Button } from './button'
-import { UiTextContext } from '../context'
+import { LocaleContext } from '../context'
import classes from '../styles/choice.module.sass'
const Choice = ({ id = '0', children = [] }) => {
- const uiText = useContext(UiTextContext)
+ const { uiText } = useContext(LocaleContext)
const [selected, setSelected] = useState(null)
const [answer, setAnswer] = useState(null)
const handleAnswer = useCallback(() => setAnswer(selected), [selected])
diff --git a/src/components/code.js b/src/components/code.js
index b0808c78a..35af28107 100644
--- a/src/components/code.js
+++ b/src/components/code.js
@@ -3,7 +3,7 @@ import { StaticQuery, graphql } from 'gatsby'
import { Hint } from './hint'
import { Button } from './button'
-import { ChapterContext, UiTextContext } from '../context'
+import { ChapterContext, LocaleContext } from '../context'
import classes from '../styles/code.module.sass'
function getFiles({ allCode }, lang) {
@@ -109,8 +109,8 @@ class CodeBlock extends React.Component {
const solutionFile = files[solutionId]
const testFile = files[testId]
return (
-
- {uiText => (
+
+ {({ uiText }) => (
{Juniper && (
)}
-
+
)
}}
/>
diff --git a/src/components/exercise.js b/src/components/exercise.js
index d4f42bc20..239023930 100644
--- a/src/components/exercise.js
+++ b/src/components/exercise.js
@@ -2,14 +2,16 @@ import React, { useRef, useCallback, useContext, useEffect } from 'react'
import classNames from 'classnames'
import { Button, CompleteButton } from './button'
-import { ChapterContext, UiTextContext } from '../context'
+import { ChapterContext, LocaleContext } from '../context'
import IconSlides from '../../static/icon_slides.svg'
+import IconVideo from '../../static/icon_video.svg'
import classes from '../styles/exercise.module.sass'
const Exercise = ({ id, title, type, children }) => {
- const uiText = useContext(UiTextContext)
+ const { uiText } = useContext(LocaleContext)
const excRef = useRef()
const excId = parseInt(id)
+ const types = type ? type.split(',').map(t => t.trim()) : []
const { activeExc, setActiveExc, completed, setCompleted } = useContext(ChapterContext)
const isExpanded = activeExc === excId
const isCompleted = completed.includes(excId)
@@ -31,7 +33,7 @@ const Exercise = ({ id, title, type, children }) => {
}, [isCompleted, completed, excId])
const rootClassNames = classNames(classes.root, {
[classes.expanded]: isExpanded,
- [classes.wide]: isExpanded && type === 'slides',
+ [classes.wide]: isExpanded && types.includes('slides'),
[classes.completed]: !isExpanded && isCompleted,
})
const titleClassNames = classNames(classes.title, {
@@ -48,7 +50,12 @@ const Exercise = ({ id, title, type, children }) => {
{title}
- {type === 'slides' && }
+ {types.includes('slides') && (
+
+ )}
+ {types.includes('video') && (
+
+ )}
{isExpanded && (
diff --git a/src/components/hint.js b/src/components/hint.js
index 2ee490675..cf4564b31 100644
--- a/src/components/hint.js
+++ b/src/components/hint.js
@@ -1,10 +1,10 @@
import React, { useState, useCallback, useContext } from 'react'
-import { UiTextContext } from '../context'
+import { LocaleContext } from '../context'
import classes from '../styles/hint.module.sass'
export const Hint = ({ expanded = false, actions = [], children }) => {
- const uiText = useContext(UiTextContext)
+ const { uiText } = useContext(LocaleContext)
const [isExpanded, setIsExpanded] = useState(expanded)
const handleExpand = useCallback(() => setIsExpanded(!isExpanded), [isExpanded])
return (
diff --git a/src/components/layout.js b/src/components/layout.js
index 99b34d366..ec9af5e9a 100644
--- a/src/components/layout.js
+++ b/src/components/layout.js
@@ -5,7 +5,7 @@ import SEO from './seo'
import { Link } from './link'
import { H3 } from './typography'
import { Logo } from './logo'
-import { UiTextContext } from '../context'
+import { LocaleContext } from '../context'
import '../styles/index.sass'
import classes from '../styles/layout.module.sass'
@@ -26,7 +26,7 @@ const Layout = ({ isHome, title, description, lang, pageName, children }) => {
return (
<>
-
+
{langs.length > 1 && (
-
+
>
)
}
diff --git a/src/components/logo.js b/src/components/logo.js
index 868622d9d..e29eb5b99 100644
--- a/src/components/logo.js
+++ b/src/components/logo.js
@@ -1,15 +1,15 @@
import React, { useContext } from 'react'
-import { UiTextContext } from '../context'
+import { LocaleContext } from '../context'
import Logos from '../../static/logos.svg'
export const Logo = ({ width = 300, height = 107, lang, className, ...props }) => {
- const uiText = useContext(UiTextContext)
+ const { title } = useContext(LocaleContext)
return (
<>