diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 7f1ca97e..74147544 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -5,7 +5,6 @@ import ErrorView from './components/Error' import LoadingPage from './containers/Loading' import StartPage from './containers/Start' import SelectTutorialPage from './containers/SelectTutorial' -import CompletedPage from './containers/Tutorial/CompletedPage' import TutorialPage from './containers/Tutorial' /* @@ -39,12 +38,8 @@ const Routes = () => { - - - - {/* Completed */} - - + + ) diff --git a/web-app/src/containers/Tutorial/CompletedPage.tsx b/web-app/src/containers/Tutorial/CompletedPage.tsx deleted file mode 100644 index 0e61aa5c..00000000 --- a/web-app/src/containers/Tutorial/CompletedPage.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import * as React from 'react' -import * as T from 'typings' -import { css, jsx } from '@emotion/core' -import Button from '../../components/Button' - -const styles = { - page: { - padding: '1rem', - }, - section: { - marginTop: '1rem', - marginBottom: '2rem', - }, - buttonContainer: { - marginTop: '1rem', - }, -} - -interface Props { - context: T.MachineContext -} - -const CompletedPage = (props: Props) => { - return ( -
-

Tutorial Complete!

-
-

Thank you for demoing the CodeRoad preview!

-
-
-

Subscribe!

-

Sign up to our mailing list to be first to hear about future tutorials.

-
- - - -
-
-
-

Contact Us

-

We'd love to hear your comments, issues, ideas & feedback.

-

- Reach out at{' '} - https://github.com/coderoad/coderoad-vscode! -

-
-
-

Continue

-

To try another tutorial, open a new VSCode workspace and launch the CodeRoad app

-
-
- ) -} - -export default CompletedPage diff --git a/web-app/src/containers/Tutorial/components/CompletedBanner.tsx b/web-app/src/containers/Tutorial/components/CompletedBanner.tsx new file mode 100644 index 00000000..31bc23ce --- /dev/null +++ b/web-app/src/containers/Tutorial/components/CompletedBanner.tsx @@ -0,0 +1,81 @@ +import * as React from 'react' +import { css, jsx } from '@emotion/core' +import { Button, Icon } from '@alifd/next' + +const styles = { + banner: { + height: 'auto', + width: '100%', + backgroundColor: 'rgb(85, 132, 255)', + color: 'white', + padding: '0.5rem 1rem', + }, + header: { + position: 'relative' as 'relative', + width: '100%', + }, + headerMessage: { + marginLeft: '0.5rem', + }, + // close: { + // position: 'absolute' as 'absolute', + // right: '0.5rem', + // top: '0.5rem', + // padding: '2px', + // }, + section: { + padding: '0rem 0.5rem 1rem 0.5rem', + }, + options: { + display: 'flex' as 'flex', + flexDirection: 'row' as 'row', + flexWrap: 'wrap' as 'wrap', + }, + optionsLeft: { + flex: 3, + }, + optionsRight: { + flex: 1, + display: 'flex' as 'flex', + justifyContent: 'flex-end' as 'flex-end', + alignItems: 'flex-end' as 'flex-end', + }, +} + +interface Props { + title: string + onRequestWorkspace(): void +} + +const CompletedBanner = (props: Props) => { + return ( +
+
+

+ + Congratulations on completing "{props.title}"! +

+
+
+
You've reached the end of the road...
+
+
+

To go down another path:

+
    +
  • - open a new VSCode workspace
  • +
  • - relaunch the CodeRoad app
  • +
  • - select a new tutorial
  • +
+
+
+ +
+
+
+
+ ) +} + +export default CompletedBanner diff --git a/web-app/src/containers/Tutorial/components/SideMenu.tsx b/web-app/src/containers/Tutorial/components/SideMenu.tsx index 08e83170..fbf21b37 100644 --- a/web-app/src/containers/Tutorial/components/SideMenu.tsx +++ b/web-app/src/containers/Tutorial/components/SideMenu.tsx @@ -23,8 +23,8 @@ const styles = { interface Props { visible: boolean toggleVisible(visible: boolean): void - page: 'level' | 'settings' | 'review' - setPage(page: 'level' | 'settings' | 'review'): void + page: 'about' | 'level' | 'review' | 'settings' + setPage(page: 'about' | 'level' | 'review' | 'settings'): void } const SideMenu = (props: Props) => { @@ -65,8 +65,20 @@ const SideMenu = (props: Props) => { Review - {/* + { + onMenuClose() + props.setPage('about') + }} + > + + About + + {/* { > Settings - */} + {' '} + */} ) diff --git a/web-app/src/containers/Tutorial/containers/About.tsx b/web-app/src/containers/Tutorial/containers/About.tsx new file mode 100644 index 00000000..f28e1d96 --- /dev/null +++ b/web-app/src/containers/Tutorial/containers/About.tsx @@ -0,0 +1,68 @@ +import * as React from 'react' +import Markdown from '../../../components/Markdown' + +const styles = { + container: { + display: 'flex' as 'flex', + flexDirection: 'column' as 'column', + }, + header: { + display: 'flex' as 'flex', + alignItems: 'center', + justifyContent: 'space-between', + height: '2rem', + backgroundColor: '#EBEBEB', + fontSize: '1rem', + lineHeight: '1rem', + padding: '10px 0.4rem', + }, + content: { + padding: '0.5rem', + }, +} + +interface Props {} + +const AboutPage = (props: Props) => { + return ( +
+
+
About CodeRoad
+
+
+ + {` +CodeRoad is an open source VSCode extension that allows you to **create** and **play** interactive coding tutorials inside VSCode. + +Learn more or contribute at [https://github.com/coderoad/coderoad-vscode](https://github.com/coderoad/coderoad-vscode). + +##### Why CodeRoad? + +Interactive learning is the most effective way to gain new skills and knowledge. CodeRoad aims to help tutorial creators develop and share interactive content with the community. + +For learners, there are a number of advantages to running tutorials inside VSCode: + +a. Learn in a real world coding environment +b. Get rapid feedback on save and helpful error messages +c.Users own the code, and can build a Git timeline and deploy a portfolio + +##### Subscribe + +Join our [mailing list](https://tiny.cc/coderoad) to hear about new tutorials & features. + +##### Contact + +We'd love to hear your feedback. + +For bugs/feature requests, reach out on GitHub. + +Otherwise, email us at [coderoadapp@gmail.com](mailto:coderoadapp@gmail.com). + +`} + +
+
+ ) +} + +export default AboutPage diff --git a/web-app/src/containers/Tutorial/containers/Review.tsx b/web-app/src/containers/Tutorial/containers/Review.tsx index 453d7faa..9cb4247a 100644 --- a/web-app/src/containers/Tutorial/containers/Review.tsx +++ b/web-app/src/containers/Tutorial/containers/Review.tsx @@ -10,6 +10,8 @@ interface Props { const styles = { container: { + height: 'auto', + width: '100%', display: 'flex' as 'flex', flexDirection: 'column' as 'column', }, diff --git a/web-app/src/containers/Tutorial/index.tsx b/web-app/src/containers/Tutorial/index.tsx index 5b884fb8..18654d42 100644 --- a/web-app/src/containers/Tutorial/index.tsx +++ b/web-app/src/containers/Tutorial/index.tsx @@ -4,6 +4,7 @@ import * as selectors from '../../services/selectors' import SideMenu from './components/SideMenu' import Level from './components/Level' import Icon from '../../components/Icon' +import AboutPage from './containers/About' import ReviewPage from './containers/Review' import Button from '../../components/Button' import ProcessMessages from '../../components/ProcessMessages' @@ -14,6 +15,7 @@ import formatLevels from './formatLevels' import Reset from './components/Reset' import Continue from './components/Continue' import ScrollContent from './components/ScrollContent' +import CompletedBanner from './components/CompletedBanner' const styles = { page: { @@ -53,6 +55,13 @@ const styles = { color: 'white', zIndex: 1000, }, + completeFooter: { + position: 'fixed' as 'fixed', + bottom: 0, + left: 0, + right: 0, + zIndex: 1000, + }, processes: { padding: '0 1rem', position: 'fixed' as 'fixed', @@ -73,7 +82,7 @@ const styles = { interface PageProps { context: T.MachineContext send(action: T.Action): void - state: string // 'Normal' | 'TestRunning' | 'TestFail' | 'TestPass' | 'LevelComplete' + state: string // 'Normal' | 'TestRunning' | 'TestFail' | 'TestPass' | 'Level.LevelComplete' } /** @@ -103,7 +112,7 @@ const TutorialPage = (props: PageProps) => { const [menuVisible, setMenuVisible] = React.useState(false) - const [page, setPage] = React.useState<'level' | 'settings' | 'review'>('level') + const [page, setPage] = React.useState<'about' | 'level' | 'review' | 'settings'>('level') // format level code with status for easy rendering const { level, levels, levelIndex, stepIndex } = formatLevels({ @@ -113,7 +122,7 @@ const TutorialPage = (props: PageProps) => { testStatus, }) - const disableOptions = processes.length > 0 || props.state === 'TestRunning' + const disableOptions = processes.length > 0 || props.state === 'Level.TestRunning' return (
@@ -125,68 +134,81 @@ const TutorialPage = (props: PageProps) => { {tutorial.summary.title}
+ {page === 'about' && } + {page === 'level' && ( )} {page === 'review' && } + {/* {page === 'settings' && } */} -
- {/* Process Modal */} - {processes.length > 0 && ( -
- -
- )} - {/* Test Fail Modal */} - {testStatus && testStatus.type === 'warning' && ( -
- -
- )} - {/* Left */} -
- {DISPLAY_RUN_TEST_BUTTON && level.status !== 'COMPLETE' ? ( - - ) : null} -
- {/* Center */} -
- + {props.state === 'Completed' ? ( +
+ props.send({ type: 'REQUEST_WORKSPACE' })} + />
- - {/* Right */} -
- {!level.steps.length ? ( -
- + ) : ( +
+ {/* Process Modal */} + {processes.length > 0 && ( +
+
- ) : props.state === 'LevelComplete' ? ( -
- + )} + {/* Test Fail Modal */} + {testStatus && testStatus.type === 'warning' && ( +
+
- ) : level.steps.length > 1 ? ( - - ) : null} + )} + {/* Left */} +
+ {DISPLAY_RUN_TEST_BUTTON && level.status !== 'COMPLETE' ? ( + + ) : null} +
+ + {/* Center */} +
+ +
+ + {/* Right */} +
+ {!level.steps.length ? ( +
+ +
+ ) : props.state === 'Level.LevelComplete' ? ( +
+ +
+ ) : level.steps.length > 1 ? ( + + ) : null} +
-
+ )}
) diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 4e62e6db..fb6efea9 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -253,6 +253,9 @@ export const createMachine = (options: any) => { target: '#select-new-tutorial', actions: ['reset'], }, + REQUEST_WORKSPACE: { + actions: 'requestWorkspaceSelect', + }, }, }, }, diff --git a/web-app/stories/About.stories.tsx b/web-app/stories/About.stories.tsx new file mode 100644 index 00000000..f3155267 --- /dev/null +++ b/web-app/stories/About.stories.tsx @@ -0,0 +1,10 @@ +import * as React from 'react' +import { storiesOf } from '@storybook/react' +import SideBarDecorator from './utils/SideBarDecorator' +import AboutPage from '../src/containers/Tutorial/containers/About' + +storiesOf('About', module) + .addDecorator(SideBarDecorator) + .add('About Page', () => { + return + }) diff --git a/web-app/stories/Completed.stories.tsx b/web-app/stories/Completed.stories.tsx index 7fe01ecf..b3c4fd64 100644 --- a/web-app/stories/Completed.stories.tsx +++ b/web-app/stories/Completed.stories.tsx @@ -1,9 +1,8 @@ -import { action } from '@storybook/addon-actions' import { storiesOf } from '@storybook/react' import React from 'react' -import CompletedPage from '../src/containers/Tutorial/CompletedPage' +import CompletedBanner from '../src/containers/Tutorial/components/CompletedBanner' import SideBarDecorator from './utils/SideBarDecorator' storiesOf('Completed', module) .addDecorator(SideBarDecorator) - .add('Page', () => ) + .add('Page', () => ) diff --git a/web-app/stories/Overview.stories.tsx b/web-app/stories/Overview.stories.tsx index 164a4e20..d43f2f6a 100644 --- a/web-app/stories/Overview.stories.tsx +++ b/web-app/stories/Overview.stories.tsx @@ -16,7 +16,7 @@ storiesOf('Overview', module) appVersions: { vscode: '0.1.0', }, - testRunner: { command: '' }, + testRunner: { command: '', args: { tap: '' } }, repo: { uri: '', branch: 'master' }, }, summary: { diff --git a/web-app/stories/Tutorial.stories.tsx b/web-app/stories/Tutorial.stories.tsx index d2017b9e..cc226800 100644 --- a/web-app/stories/Tutorial.stories.tsx +++ b/web-app/stories/Tutorial.stories.tsx @@ -146,7 +146,7 @@ storiesOf('Tutorial', module) position: { levelId: '1', stepId: '1.2' }, progress: { levels: {}, steps: {}, complete: false }, } - return + return }) .add('1.3 Level Complete', () => { const levelComplete = { @@ -154,7 +154,7 @@ storiesOf('Tutorial', module) position: { levelId: '1', stepId: '1.2' }, progress: { levels: {}, steps: { '1.1': true }, complete: false }, } - return + return }) .add('3.1 Level Start', () => { const newLevel = { @@ -162,7 +162,7 @@ storiesOf('Tutorial', module) position: { levelId: '1', stepId: '1.2' }, progress: { levels: { '1': true, '2': true }, steps: {}, complete: false }, } - return + return }) .add('3.3 Final', () => { const lastLevel = { @@ -170,5 +170,13 @@ storiesOf('Tutorial', module) position: { levelId: '3', stepId: '3.3' }, progress: { levels: { '3': true }, steps: { '3.3': true }, complete: true }, } - return + return + }) + .add('3.3 Completed', () => { + const lastLevel = { + ...context, + position: { levelId: '3', stepId: '3.3' }, + progress: { levels: { '3': true }, steps: { '3.3': true }, complete: true }, + } + return })