├── .gitignore
├── __mocks__
├── styleMock.js
├── fileMock.js
└── test.png
├── src
├── styles
│ ├── vars.css
│ ├── font.css
│ ├── styles.css
│ └── colors.css
├── components
│ ├── Deck.css
│ ├── Highlight.css
│ ├── Title.css
│ ├── Subtitle.css
│ ├── Text.css
│ ├── __snapshots__
│ │ ├── Text.test.js.snap
│ │ ├── Title.test.js.snap
│ │ ├── Subtitle.test.js.snap
│ │ ├── Slide.test.js.snap
│ │ ├── Footer.test.js.snap
│ │ ├── Highlight.test.js.snap
│ │ ├── Image.test.js.snap
│ │ ├── Quote.test.js.snap
│ │ ├── Video.test.js.snap
│ │ ├── List.test.js.snap
│ │ ├── Deck.test.js.snap
│ │ ├── Columns.test.js.snap
│ │ ├── Navigation.test.js.snap
│ │ ├── Browser.test.js.snap
│ │ └── Code.test.js.snap
│ ├── Video.test.js
│ ├── Slide.css
│ ├── Text.test.js
│ ├── Footer.test.js
│ ├── List.css
│ ├── Slide.test.js
│ ├── Title.test.js
│ ├── Code.test.js
│ ├── Browser.test.js
│ ├── Quote.test.js
│ ├── Subtitle.test.js
│ ├── Highlight.test.js
│ ├── Image.test.js
│ ├── Navigation.test.js
│ ├── List.test.js
│ ├── Deck.test.js
│ ├── Columns.test.js
│ ├── Footer.css
│ ├── Text.js
│ ├── Title.js
│ ├── Video.css
│ ├── Columns.css
│ ├── Subtitle.js
│ ├── Quote.css
│ ├── Image.css
│ ├── Highlight.js
│ ├── Columns.js
│ ├── Quote.js
│ ├── Slide.js
│ ├── Footer.js
│ ├── PresenterNotes.css
│ ├── Browser.js
│ ├── Navigation.css
│ ├── Navigation.js
│ ├── List.js
│ ├── Video.js
│ ├── Code.js
│ ├── Browser.css
│ ├── Image.js
│ ├── Code.css
│ ├── PresenterNotes.js
│ └── Deck.js
├── services
│ └── Keyboard.js
└── index.js
├── .eslintignore
├── .babelrc
├── postcss.config.js
├── .npmignore
├── .travis.yml
├── .eslintrc
├── webpack.config.babel.js
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/__mocks__/styleMock.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/__mocks__/fileMock.js:
--------------------------------------------------------------------------------
1 | module.exports = 'test-file-stub';
2 |
--------------------------------------------------------------------------------
/src/styles/vars.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --breakpoint: 600px;
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | .babelrc
4 | .eslintrc
5 | .eslintignore
6 |
--------------------------------------------------------------------------------
/__mocks__/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sambego/diorama/HEAD/__mocks__/test.png
--------------------------------------------------------------------------------
/src/components/Deck.css:
--------------------------------------------------------------------------------
1 | .swipe,
2 | .deck {
3 | width: 100vw;
4 | height: 100vh;
5 | overflow: hidden;
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/Highlight.css:
--------------------------------------------------------------------------------
1 | .highlight {
2 | padding: 0.5rem;
3 | background-color: var(--color-primary);
4 | }
5 |
--------------------------------------------------------------------------------
/src/styles/font.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Import Google Montserrat
3 | */
4 | @import url('https://fonts.googleapis.com/css?family=Montserrat:400,700');
5 |
--------------------------------------------------------------------------------
/src/components/Title.css:
--------------------------------------------------------------------------------
1 | .title {
2 | margin: 0;
3 | max-width: 80vw;
4 | font-size: 6vw;
5 | font-weight: 700;
6 | text-transform: uppercase;
7 | }
8 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env", "@babel/preset-react"],
3 | "plugins": ["@babel/plugin-proposal-class-properties", "transform-function-bind"]
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/Subtitle.css:
--------------------------------------------------------------------------------
1 | .subtitle {
2 | margin: 0;
3 | max-width: 80%;
4 | font-size: 4.5vw;
5 | font-weight: 700;
6 | text-transform: uppercase;
7 | }
8 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require("postcss-import")(),
4 | require("postcss-nested")(),
5 | require("autoprefixer")(),
6 | ]
7 | };
8 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # .npmignore
2 |
3 | __mocks__
4 | src
5 | .babelrc
6 | .eslintrc
7 | .eslintignore
8 | .gitignore
9 | .travis.yml
10 | postcss.config.js
11 | webpack.config.babel.js
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - '10'
5 |
6 | sudo: false
7 |
8 | cache:
9 | directories:
10 | - 'node_modules'
11 |
12 | script:
13 | - npm run test
14 |
--------------------------------------------------------------------------------
/src/components/Text.css:
--------------------------------------------------------------------------------
1 | .text {
2 | margin: 0;
3 | max-width: 80vw;
4 | font-size: 3.5vw;
5 | line-height: 1.7;
6 | }
7 |
8 | @media (min-width: 600px) {
9 | .text {
10 | font-size: 2.5vw;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Text.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 | Text content
9 |
10 | `;
11 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Title.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 | Title content
9 |
10 | `;
11 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Subtitle.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 | Subtitle content
9 |
10 | `;
11 |
--------------------------------------------------------------------------------
/src/components/Video.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Video from './Video';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create().toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Slide.css:
--------------------------------------------------------------------------------
1 | .slide {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
6 | .content {
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | flex-direction: column;
11 | width: 100%;
12 | height: 100%;
13 | text-align: center;
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Text.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Text from './Text';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create(Text content).toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Footer.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Footer from './Footer';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create().toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/List.css:
--------------------------------------------------------------------------------
1 | .list {
2 | padding: 0;
3 | margin: 0;
4 | list-style: none;
5 | }
6 |
7 | .ol {
8 | margin: 0;
9 | max-width: 80vw;
10 |
11 | text-align: left;
12 | }
13 |
14 | .item {
15 | padding: 2rem 0;
16 | margin: 0;
17 |
18 | font-size: 3vw;
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/Slide.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Slide from './Slide';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create(Slide content).toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Title.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Title from './Title';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create(Title content).toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Code.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Code from './Code';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create().toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Browser.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Browser from './Browser';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create().toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Quote.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Quote from './Quote';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create(Nice quote
).toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Subtitle.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Subtitle from './Subtitle';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create(Subtitle content).toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Highlight.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Highlight from './Highlight';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer.create(Highlighted text).toJSON();
7 | expect(tree).toMatchSnapshot();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Slide.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 |
11 | Slide content
12 |
13 |
14 | `;
15 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Footer.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
14 | `;
15 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Highlight.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
12 | Highlighted text
13 |
14 | `;
15 |
--------------------------------------------------------------------------------
/src/components/Image.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Image from './Image';
4 |
5 | import test from '../../__mocks__/test.png';
6 |
7 | it('renders correctly', () => {
8 | const tree = renderer.create().toJSON();
9 | expect(tree).toMatchSnapshot();
10 | });
11 |
--------------------------------------------------------------------------------
/src/components/Navigation.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Navigation from './Navigation';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer
7 | .create( true} onNextSlide={() => true} />)
8 | .toJSON();
9 | expect(tree).toMatchSnapshot();
10 | });
11 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Image.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
7 |

13 |
14 | `;
15 |
--------------------------------------------------------------------------------
/src/components/List.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import List from './List';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer
7 | .create(
8 |
9 | one
10 | two
11 |
,
12 | )
13 | .toJSON();
14 | expect(tree).toMatchSnapshot();
15 | });
16 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Quote.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 | Array [
5 |
9 | Nice quote
10 |
,
11 |
14 | Sam Bellen
15 | ,
16 | ]
17 | `;
18 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Video.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 |
15 |
16 | `;
17 |
--------------------------------------------------------------------------------
/src/components/Deck.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Deck from './Deck';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer
7 | .create(
8 |
9 | Slide 1
10 | Slide 2
11 | ,
12 | )
13 | .toJSON();
14 | expect(tree).toMatchSnapshot();
15 | });
16 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": ["airbnb"],
4 | "env": {
5 | "node": true,
6 | "jest": true
7 | },
8 | "rules": {
9 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
10 | "import/no-unresolved": [1, { ignore: ["react", "propt-types"] }]
11 | },
12 | "globals": {
13 | "window": true,
14 | "document": true,
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/Columns.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 | import Columns from './Columns';
4 |
5 | it('renders correctly', () => {
6 | const tree = renderer
7 | .create(
8 |
9 | Column 1
10 | Column 2
11 | ,
12 | )
13 | .toJSON();
14 | expect(tree).toMatchSnapshot();
15 | });
16 |
--------------------------------------------------------------------------------
/src/components/Footer.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | position: fixed;
3 | bottom: 0;
4 | left: 0;
5 | right: 0;
6 | z-index: 1;
7 | display: flex;
8 | justify-content: space-between;
9 | width: 100%;
10 | padding: 2rem 4rem;
11 | font-size: 1.5vw;
12 | font-weight: 700;
13 | }
14 |
15 | .left {
16 | text-alignn: left;
17 | }
18 |
19 | .right {
20 | margin-left: auto;
21 | text-align: right;
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/List.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 | -
11 | one
12 |
13 | -
16 | two
17 |
18 |
19 | `;
20 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Deck.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
11 |
14 |
18 | Slide 1
19 |
20 |
21 |
22 | `;
23 |
--------------------------------------------------------------------------------
/src/styles/styles.css:
--------------------------------------------------------------------------------
1 | @import 'colors';
2 | @import 'font';
3 |
4 | * {
5 | box-sizing: border-box;
6 | }
7 |
8 | html,
9 | body {
10 | width: 100%;
11 | height: 100%;
12 | padding: 0;
13 | margin: 0;
14 | }
15 |
16 | html {
17 | font-size: 10px;
18 | }
19 |
20 | body {
21 | font-size: 1.6rem;
22 | font-family: 'montserrat', Helvetica, Arial, sans-serif;
23 | }
24 |
25 | a {
26 | color: var(--color-primary);
27 | text-decoration: none;
28 | border-bottom: 2px solid var(--color-primary);
29 | }
30 |
--------------------------------------------------------------------------------
/src/services/Keyboard.js:
--------------------------------------------------------------------------------
1 | import keycode from 'keycode';
2 |
3 | export default class Keyboard {
4 | static isKey(event, key, callback) {
5 | if (keycode(event) === key) {
6 | callback();
7 | }
8 | }
9 |
10 | static on(key, callback) {
11 | const listener = event => this.isKey(event, key, callback);
12 |
13 | window.addEventListener('keyup', listener);
14 |
15 | return listener;
16 | }
17 |
18 | static off(listener) {
19 | window.removeEventListener('keyup', listener);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/Text.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Text.css';
5 |
6 | const Text = ({ children, style, className }) => (
7 |
8 | {children}
9 |
10 | );
11 |
12 | Text.propTypes = {
13 | children: PropTypes.node.isRequired,
14 | className: PropTypes.string,
15 | style: PropTypes.shape({}),
16 | };
17 |
18 | Text.defaultProps = {
19 | className: '',
20 | style: {},
21 | };
22 |
23 | export default Text;
24 |
--------------------------------------------------------------------------------
/src/components/Title.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Title.css';
5 |
6 | const Title = ({ children, style, className }) => (
7 |
8 | {children}
9 |
10 | );
11 |
12 | Title.propTypes = {
13 | children: PropTypes.node.isRequired,
14 | className: PropTypes.string,
15 | style: PropTypes.shape({}),
16 | };
17 |
18 | Title.defaultProps = {
19 | className: '',
20 | style: {},
21 | };
22 |
23 | export default Title;
24 |
--------------------------------------------------------------------------------
/src/components/Video.css:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 80vw;
3 | height: calc((80vw / 16) * 9);
4 | }
5 |
6 | .full {
7 | position: absolute;
8 | top: 0;
9 | bottom: 0;
10 | left: 0;
11 | right: 0;
12 | z-index: 0;
13 |
14 | width: 100vw;
15 | height: 100vh;
16 | object-fit: cover;
17 |
18 | video {
19 | width: 100vw;
20 | height: 100vh;
21 | object-fit: cover;
22 | }
23 | }
24 |
25 | .overlay {
26 | position: absolute;
27 | top: 0;
28 | bottom: 0;
29 | left: 0;
30 | right: 0;
31 | z-index: 1;
32 |
33 | opacity: 0.6;
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Columns.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
7 |
15 | Column 1
16 |
17 |
25 | Column 2
26 |
27 |
28 | `;
29 |
--------------------------------------------------------------------------------
/src/components/Columns.css:
--------------------------------------------------------------------------------
1 | .columns {
2 | display: flex;
3 | flex-direction: column;
4 | width: 100vw;
5 | height: 100vh;
6 | min-height: 400px;
7 | }
8 |
9 | .column {
10 | flex: 1;
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | flex-direction: column;
15 | width: 100%;
16 | height: 100%;
17 | text-align: center;
18 | }
19 |
20 | @media (min-width: 600px) {
21 | .columns {
22 | flex-direction: row;
23 | }
24 | }
25 |
26 | [class~='diorama-presenter-preview'] {
27 | .columns {
28 | flex-direction: row;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/Subtitle.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Subtitle.css';
5 |
6 | const Subtitle = ({ children, style, className }) => (
7 |
8 | {children}
9 |
10 | );
11 |
12 | Subtitle.propTypes = {
13 | children: PropTypes.node.isRequired,
14 | className: PropTypes.string,
15 | style: PropTypes.shape({}),
16 | };
17 |
18 | Subtitle.defaultProps = {
19 | className: '',
20 | style: {},
21 | };
22 |
23 | export default Subtitle;
24 |
--------------------------------------------------------------------------------
/src/components/Quote.css:
--------------------------------------------------------------------------------
1 | .quote {
2 | margin: 0 auto;
3 | max-width: 80vw;
4 |
5 | font-weight: 700;
6 | font-size: 5vw;
7 |
8 | &::before {
9 | content: '“';
10 | }
11 |
12 | &::after {
13 | content: '”';
14 | }
15 | }
16 |
17 | .cite {
18 | margin: 1rem auto 0 auto;
19 | padding-right: 5rem;
20 | max-width: 80vw;
21 | font-size: 3vw;
22 | text-align: right;
23 |
24 | &::before {
25 | content: '-';
26 | }
27 |
28 | &::after {
29 | content: '-';
30 | }
31 | }
32 |
33 | @media (min-width: 600px) {
34 | .cite {
35 | margin: 1rem auto 0 auto;
36 | padding-right: 5rem;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/Image.css:
--------------------------------------------------------------------------------
1 | .container {
2 | position: relative;
3 | }
4 |
5 | .image {
6 | width: 100%;
7 | max-width: 80vw;
8 | max-height: 80vh;
9 | object-fit: cover;
10 | object-position: center;
11 | }
12 |
13 | .full {
14 | display: flex;
15 | align-items: center;
16 | justify-content: center;
17 | flex-direction: column;
18 | width: 100%;
19 | height: 100%;
20 | max-width: 100%;
21 | max-height: 100%;
22 | }
23 |
24 | .overlay {
25 | position: absolute;
26 | top: 0;
27 | bottom: 0;
28 | left: 0;
29 | right: 0;
30 | width: 100%;
31 | height: 100%;
32 | mix-blend-mode: multiply;
33 | }
34 |
35 | .contain {
36 | object-fit: contain;
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/Highlight.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Highlight.css';
5 |
6 | const Highlight = ({
7 | children, style, className, color,
8 | }) => (
9 |
10 | {children}
11 |
12 | );
13 |
14 | Highlight.propTypes = {
15 | children: PropTypes.node.isRequired,
16 | className: PropTypes.string,
17 | color: PropTypes.string,
18 | style: PropTypes.shape({}),
19 | };
20 |
21 | Highlight.defaultProps = {
22 | className: '',
23 | color: undefined,
24 | style: {},
25 | };
26 |
27 | export default Highlight;
28 |
--------------------------------------------------------------------------------
/src/components/Columns.js:
--------------------------------------------------------------------------------
1 | import React, { cloneElement } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Columns.css';
5 |
6 | const Columns = ({ children, className }) => {
7 | const renderColumns = () => children.map((child, index) => cloneElement(child, {
8 | className: `${styles.column} diorama-column ${className} `,
9 | key: index,
10 | style: { maxWidth: `${100 / children}%` },
11 | }));
12 |
13 | return {renderColumns()}
;
14 | };
15 |
16 | Columns.propTypes = {
17 | children: PropTypes.node.isRequired,
18 | className: PropTypes.string,
19 | };
20 |
21 | Columns.defaultProps = {
22 | className: '',
23 | };
24 |
25 | export default Columns;
26 |
--------------------------------------------------------------------------------
/src/components/Quote.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Quote.css';
5 |
6 | const Quote = ({
7 | children, quotee, style, className,
8 | }) => (
9 | <>
10 |
11 | {children}
12 |
13 | {quotee && {quotee}}
14 | >
15 | );
16 |
17 | Quote.propTypes = {
18 | children: PropTypes.node.isRequired,
19 | className: PropTypes.string,
20 | style: PropTypes.shape({}),
21 | quotee: PropTypes.node,
22 | };
23 |
24 | Quote.defaultProps = {
25 | className: '',
26 | style: {},
27 | quotee: undefined,
28 | };
29 |
30 | export default Quote;
31 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Navigation.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
35 | `;
36 |
--------------------------------------------------------------------------------
/src/components/Slide.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Slide.css';
5 |
6 | const Slide = ({ children, style, className }) => (
7 |
10 | );
11 |
12 | /* eslint-disable react/no-unused-prop-types */
13 | Slide.propTypes = {
14 | children: PropTypes.node.isRequired,
15 | className: PropTypes.string,
16 | notes: PropTypes.string,
17 | style: PropTypes.shape({}),
18 | };
19 | /* eslint-enable react/no-unused-prop-types */
20 |
21 | Slide.defaultProps = {
22 | className: '',
23 | notes: undefined,
24 | style: {},
25 | };
26 |
27 | export default Slide;
28 |
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Footer.css';
5 |
6 | const Footer = ({
7 | left, right, style, className,
8 | }) => (
9 |
13 | );
14 |
15 | Footer.propTypes = {
16 | left: PropTypes.node,
17 | right: PropTypes.node,
18 | className: PropTypes.string,
19 | style: PropTypes.shape({}),
20 | };
21 |
22 | Footer.defaultProps = {
23 | left: undefined,
24 | right: undefined,
25 | className: '',
26 | style: {},
27 | };
28 |
29 | export default Footer;
30 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Browser.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
38 | `;
39 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Deck from './components/Deck';
2 | import Slide from './components/Slide';
3 | import Title from './components/Title';
4 | import Subtitle from './components/Subtitle';
5 | import Columns from './components/Columns';
6 | import Image from './components/Image';
7 | import Text from './components/Text';
8 | import Code from './components/Code';
9 | import Footer from './components/Footer';
10 | import Highlight from './components/Highlight';
11 | import Quote from './components/Quote';
12 | import List from './components/List';
13 | import Browser from './components/Browser';
14 | import Video from './components/Video';
15 |
16 | export {
17 | Deck,
18 | Slide,
19 | Title,
20 | Subtitle,
21 | Columns,
22 | Image,
23 | Text,
24 | Code,
25 | Footer,
26 | Highlight,
27 | Quote,
28 | List,
29 | Browser,
30 | Video,
31 | };
32 |
--------------------------------------------------------------------------------
/src/styles/colors.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --color-gray-0: #1b2b34;
3 | --color-gray-1: #343d46;
4 | --color-gray-2: #4f5b66;
5 | --color-gray-3: #65737e;
6 | --color-gray-4: #a7adba;
7 | --color-gray-5: #c0c5ce;
8 | --color-gray-6: #cdd3de;
9 | --color-gray-7: #d8dee9;
10 |
11 | --color-gray-dark: var(--color-gray-0);
12 | --color-gray-medium: var(--color-gray-4);
13 | --color-gray-light: var(--color-gray-7);
14 |
15 | --color-red: #ec5f67;
16 | --color-orange: #f99157;
17 | --color-yellow: #fac863;
18 | --color-green: #99c794;
19 | --color-teal: #5fb3b3;
20 | --color-blue: #6699cc;
21 | --color-pink: #c594c5;
22 | --color-brown: #ab7967;
23 |
24 | --color-primary: var(--color-green);
25 | --color-seconday: var(--color-teal);
26 |
27 | --color-danger: var(--color-red);
28 | --color-success: var(--color-green);
29 | --color-info: var(--color-blue);
30 | --color-warning: var(--color-yellow);
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/PresenterNotes.css:
--------------------------------------------------------------------------------
1 | .presenter {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100%;
5 | background: var(--color-gray-0);
6 | }
7 |
8 | .slides {
9 | display: flex;
10 | flex-direction: row;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100%;
14 | min-height: calc(((40vw / 16) * 9) + 4rem);
15 | }
16 |
17 | .slide,
18 | .next {
19 | width: 40vw;
20 | height: calc((40vw / 16) * 9);
21 | padding: 0;
22 | margin: 2rem;
23 | background: white;
24 | border: 2px solid var(--color-gray-4);
25 | }
26 |
27 | .notes {
28 | display: block;
29 | height: 100%;
30 | padding: 2rem;
31 | font-size: 4rem;
32 | background: var(--color-gray-2);
33 | color: white;
34 | }
35 |
36 | .meta {
37 | display: flex;
38 | flex-direction: row;
39 | justify-content: space-between;
40 | padding: 1rem 2rem;
41 | min-height: 5.5rem;
42 | background: var(--color-gray-0);
43 | font-size: 3rem;
44 | color: white;
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/Browser.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Browser.css';
5 |
6 | const Browser = ({ style, className, url }) => (
7 |
18 | );
19 |
20 | Browser.propTypes = {
21 | className: PropTypes.string,
22 | url: PropTypes.string.isRequired,
23 | style: PropTypes.shape({}),
24 | };
25 |
26 | Browser.defaultProps = {
27 | className: '',
28 | style: {},
29 | };
30 |
31 | export default Browser;
32 |
--------------------------------------------------------------------------------
/src/components/Navigation.css:
--------------------------------------------------------------------------------
1 | .navigation {
2 | position: fixed;
3 | bottom: 2rem;
4 | right: 4rem;
5 | z-index: 2;
6 | background: none;
7 | }
8 |
9 | .list {
10 | display: flex;
11 | margin: 0;
12 | padding: 0;
13 | background: none;
14 | }
15 |
16 | .item {
17 | max-width: 2rem;
18 | margin: 0 2rem;
19 | padding: 0;
20 | list-style: none;
21 | }
22 |
23 | .previous,
24 | .next {
25 | transition: border-color 0.2s ease-in-out;
26 | background: none;
27 | font-size: 0;
28 | cursor: pointer;
29 | }
30 |
31 | .previous {
32 | width: 0;
33 | height: 0;
34 | border-top: 1.5rem solid transparent;
35 | border-bottom: 1.5rem solid transparent;
36 | border-right: 2rem solid var(--color-gray-0);
37 | border-left: none;
38 |
39 | &:hover {
40 | border-right: 2rem solid var(--color-gray-2);
41 | }
42 | }
43 |
44 | .next {
45 | width: 0;
46 | height: 0;
47 | border-top: 1.5rem solid transparent;
48 | border-bottom: 1.5rem solid transparent;
49 | border-left: 2rem solid var(--color-gray-0);
50 | border-right: none;
51 |
52 | &:hover {
53 | border-left: 2rem solid var(--color-gray-2);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | export default env => ({
4 | entry: './src/index.js',
5 | output: {
6 | path: path.resolve(__dirname, 'dist'),
7 | filename: 'index.js',
8 | libraryTarget: 'umd',
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.css$/,
14 | exclude: /node_modules/,
15 | use: [
16 | 'style-loader',
17 | {
18 | loader: 'css-loader',
19 | options: { modules: true, importLoaders: 1 },
20 | },
21 | 'postcss-loader',
22 | ],
23 | },
24 | {
25 | test: /\.css$/,
26 | include: /node_modules/,
27 | use: [
28 | 'style-loader',
29 | {
30 | loader: 'css-loader',
31 | options: { importLoaders: 1 },
32 | },
33 | 'postcss-loader',
34 | ],
35 | },
36 | {
37 | test: /\.(js|jsx)$/,
38 | exclude: /node_modules/,
39 | use: ['babel-loader', 'eslint-loader'],
40 | },
41 | ],
42 | },
43 | externals: {
44 | react: 'react',
45 | 'react-dom': 'react-dom',
46 | },
47 | });
48 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/Code.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
8 |
11 |
14 |
17 |
20 |
23 | javascript
24 |
25 |
26 |
29 |
30 | const foo = () => 'bar';",
34 | }
35 | }
36 | />
37 |
38 |
39 |
40 | `;
41 |
--------------------------------------------------------------------------------
/src/components/Navigation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './Navigation.css';
5 |
6 | const Navigation = ({
7 | onPreviousSlide, onNextSlide, className, style,
8 | }) => (
9 |
27 | );
28 |
29 | Navigation.propTypes = {
30 | className: PropTypes.string,
31 | onPreviousSlide: PropTypes.func.isRequired,
32 | onNextSlide: PropTypes.func.isRequired,
33 | style: PropTypes.shape({}),
34 | };
35 |
36 | Navigation.defaultProps = {
37 | className: '',
38 | style: {},
39 | };
40 |
41 | export default Navigation;
42 |
--------------------------------------------------------------------------------
/src/components/List.js:
--------------------------------------------------------------------------------
1 | import React, { cloneElement } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import styles from './List.css';
5 |
6 | const List = ({
7 | children, ordered, style, className,
8 | }) => {
9 | const renderItems = () => {
10 | if (Array.isArray(children)) {
11 | return children.map((child, index) => cloneElement(child, {
12 | className: `${styles.item} diorama-list-item`,
13 | key: index,
14 | }));
15 | }
16 |
17 | return cloneElement(children, {
18 | className: `${styles.item} diorama-list-item`,
19 | });
20 | };
21 |
22 | if (ordered) {
23 | return (
24 |
25 | {renderItems()}
26 |
27 | );
28 | }
29 |
30 | return (
31 |
32 | {renderItems()}
33 |
34 | );
35 | };
36 |
37 | List.propTypes = {
38 | children: PropTypes.node.isRequired,
39 | className: PropTypes.string,
40 | ordered: PropTypes.bool,
41 | style: PropTypes.shape({}),
42 | };
43 |
44 | List.defaultProps = {
45 | className: '',
46 | ordered: false,
47 | style: {},
48 | };
49 |
50 | export default List;
51 |
--------------------------------------------------------------------------------
/src/components/Video.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | import styles from './Video.css';
5 |
6 | const Video = ({
7 | src, color, full, autoplay, loop, style, className,
8 | }) => {
9 | const classes = classnames(
10 | styles.video,
11 | {
12 | [styles.full]: full,
13 | },
14 | className,
15 | 'diorama-video-container',
16 | );
17 |
18 | return (
19 |
20 |
21 | {color ? (
22 |
28 | ) : null}
29 |
30 | );
31 | };
32 |
33 | Video.propTypes = {
34 | autoplay: PropTypes.bool,
35 | loop: PropTypes.bool,
36 | full: PropTypes.bool,
37 | color: PropTypes.string,
38 | style: PropTypes.shape({}),
39 | src: PropTypes.string.isRequired,
40 | className: PropTypes.string,
41 | };
42 |
43 | Video.defaultProps = {
44 | autoplay: false,
45 | loop: false,
46 | full: false,
47 | color: undefined,
48 | style: {},
49 | className: '',
50 | };
51 |
52 | export default Video;
53 |
--------------------------------------------------------------------------------
/src/components/Code.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Prism from 'prismjs';
4 |
5 | import 'prismjs/themes/prism.css';
6 | import styles from './Code.css';
7 |
8 | /* eslint-disable react/no-danger */
9 | const Code = ({
10 | code, lang, style, className,
11 | }) => (
12 |
13 |
14 |
15 |
16 |
17 | {lang}
18 |
19 |
28 |
29 | );
30 | /* eslint-enable react/no-danger */
31 |
32 | Code.propTypes = {
33 | className: PropTypes.string,
34 | code: PropTypes.string.isRequired,
35 | lang: PropTypes.string,
36 | style: PropTypes.shape({}),
37 | };
38 |
39 | Code.defaultProps = {
40 | className: '',
41 | lang: 'javascript',
42 | style: {},
43 | };
44 |
45 | export default Code;
46 |
--------------------------------------------------------------------------------
/src/components/Browser.css:
--------------------------------------------------------------------------------
1 | .browser {
2 | width: 80vw;
3 | height: 80vh;
4 | background: var(--color-gray-7);
5 | border-radius: 0.5rem;
6 | box-shadow: 1.5rem 1.5rem 5rem 0 rgba(27, 43, 52, 0.2),
7 | -1.5rem -1.5rem 5rem 0 rgba(27, 43, 52, 0.2), -1.5rem 1.5rem 5rem 0 rgba(27, 43, 52, 0.2),
8 | 1.5rem -1.5rem 5rem 0 rgba(27, 43, 52, 0.2);
9 | }
10 |
11 | .header {
12 | display: flex;
13 | flex-flow: row nowrap;
14 | justify-content: flex-start;
15 | padding: 1rem 2rem;
16 | text-align: left;
17 | background: var(--color-gray-medium);
18 | border-radius: 0.5rem 0.5rem 0 0;
19 | }
20 |
21 | .traffic {
22 | display: flex;
23 | align-items: center;
24 | justify-content: center;
25 | min-width: 7rem;
26 | }
27 |
28 | .red,
29 | .yellow,
30 | .green {
31 | align-self: center;
32 | display: inline-block;
33 | width: 1.2rem;
34 | height: 1.2rem;
35 | margin: 0 0.5rem 0 0;
36 | border-radius: 50%;
37 | }
38 |
39 | .red {
40 | background: var(--color-red);
41 | }
42 |
43 | .yellow {
44 | background: var(--color-yellow);
45 | }
46 |
47 | .green {
48 | background: var(--color-green);
49 | }
50 |
51 | .address {
52 | width: 100%;
53 | padding: 1rem 2rem;
54 | margin: 0 2rem 0 0;
55 | background: #fff;
56 | border: none;
57 | border-radius: 2rem;
58 | outline: 0;
59 | font-size: 1.6rem;
60 | text-align: center;
61 | }
62 |
63 | .iframe {
64 | width: 100%;
65 | height: calc(100% - 6rem);
66 | }
67 |
--------------------------------------------------------------------------------
/src/components/Image.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | import styles from './Image.css';
5 |
6 | const Image = ({
7 | alt, src, style, full, color, className, contain,
8 | }) => {
9 | const containerClasses = classnames(
10 | styles.container,
11 | {
12 | [styles.full]: full,
13 | },
14 | 'diorama-image-container',
15 | );
16 | const imageClasses = classnames(
17 | styles.image,
18 | {
19 | [styles.full]: full,
20 | [styles.contain]: contain,
21 | [className]: className !== '',
22 | },
23 | 'diorama-image',
24 | );
25 |
26 | return (
27 |
28 | {color && (
29 |
33 | )}
34 |

35 |
36 | );
37 | };
38 |
39 | Image.propTypes = {
40 | alt: PropTypes.string.isRequired,
41 | color: PropTypes.string,
42 | className: PropTypes.string,
43 | contain: PropTypes.bool,
44 | full: PropTypes.bool,
45 | style: PropTypes.shape({}),
46 | src: PropTypes.string.isRequired,
47 | };
48 |
49 | Image.defaultProps = {
50 | color: undefined,
51 | className: '',
52 | contain: false,
53 | full: false,
54 | style: {},
55 | };
56 |
57 | export default Image;
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sambego/diorama",
3 | "version": "1.1.4",
4 | "description": "A react library to create presentations",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "build:dev": "webpack --mode development --watch",
8 | "build:prod": "webpack --mode production",
9 | "test": "jest",
10 | "test:watch": "jest --watch"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+ssh://git@github.com/Sambego/diorama.git"
15 | },
16 | "keywords": [
17 | "react",
18 | "diorama",
19 | "slides",
20 | "presentation"
21 | ],
22 | "author": "Sam Bellen",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/Sambego/diorama/issues"
26 | },
27 | "homepage": "https://github.com/Sambego/diorama#readme",
28 | "peerDependencies": {
29 | "prop-types": "^15.6.2",
30 | "react": "^16.6.3",
31 | "react-dom": "^16.6.3"
32 | },
33 | "devDependencies": {
34 | "@babel/core": "^7.2.0",
35 | "@babel/plugin-proposal-class-properties": "^7.2.1",
36 | "@babel/preset-env": "^7.2.0",
37 | "@babel/preset-react": "^7.0.0",
38 | "@babel/register": "^7.0.0",
39 | "autoprefixer": "^9.4.2",
40 | "babel-core": "^7.0.0-0",
41 | "babel-eslint": "^10.0.1",
42 | "babel-jest": "^23.6.0",
43 | "babel-loader": "^8.0.4",
44 | "babel-plugin-transform-function-bind": "^6.22.0",
45 | "css-loader": "^1.0.1",
46 | "eslint": "^5.9.0",
47 | "eslint-config-airbnb": "^17.1.0",
48 | "eslint-loader": "^2.1.1",
49 | "eslint-plugin-import": "^2.14.0",
50 | "eslint-plugin-jsx-a11y": "^6.1.2",
51 | "eslint-plugin-react": "^7.11.1",
52 | "identity-obj-proxy": "^3.0.0",
53 | "jest": "^23.6.0",
54 | "postcss-import": "^12.0.1",
55 | "postcss-loader": "^3.0.0",
56 | "postcss-nested": "^4.1.0",
57 | "react": "^16.6.3",
58 | "react-dom": "^16.6.3",
59 | "react-test-renderer": "^16.6.3",
60 | "style-loader": "^0.23.1",
61 | "webpack": "^4.27.1",
62 | "webpack-cli": "^3.1.2"
63 | },
64 | "dependencies": {
65 | "classnames": "^2.2.6",
66 | "keycode": "^2.2.0",
67 | "prismjs": "^1.15.0",
68 | "react-easy-swipe": "^0.0.17"
69 | },
70 | "jest": {
71 | "moduleNameMapper": {
72 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js",
73 | "\\.(css)$": "identity-obj-proxy"
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/Code.css:
--------------------------------------------------------------------------------
1 | .code {
2 | padding: 1rem;
3 | min-width: 80vw;
4 | max-width: 80vw;
5 |
6 | background: var(--color-gray-dark);
7 |
8 | box-shadow: 1.5rem 1.5rem 5rem 0 rgba(27, 43, 52, 0.2),
9 | -1.5rem -1.5rem 5rem 0 rgba(27, 43, 52, 0.2), -1.5rem 1.5rem 5rem 0 rgba(27, 43, 52, 0.2),
10 | 1.5rem -1.5rem 5rem 0 rgba(27, 43, 52, 0.2);
11 | border-radius: 0.5rem;
12 |
13 | text-align: left;
14 |
15 | code {
16 | display: block;
17 | }
18 |
19 | pre {
20 | padding: 0;
21 | margin: 0;
22 | background: none;
23 | text-align: left;
24 | }
25 | }
26 |
27 | .header {
28 | display: flex;
29 | flex-flow: row nowrap;
30 | justify-content: flex-start;
31 | padding: 0 1rem;
32 | text-align: left;
33 | }
34 |
35 | .red,
36 | .yellow,
37 | .green {
38 | align-self: center;
39 | display: inline-block;
40 | width: 1.2rem;
41 | height: 1.2rem;
42 | margin: 0 0.5rem 0 0;
43 | border-radius: 50%;
44 | }
45 |
46 | .red {
47 | background: var(--color-red);
48 | }
49 |
50 | .yellow {
51 | background: var(--color-yellow);
52 | }
53 |
54 | .green {
55 | background: var(--color-green);
56 | }
57 |
58 | .lang {
59 | display: inline-block;
60 | flex: 1;
61 | text-align: center;
62 | color: white;
63 | }
64 |
65 | .snippet {
66 | padding: 2rem 1rem 1rem;
67 | code,
68 | pre {
69 | color: var(--color-gray-6);
70 | font-size: 2vw;
71 | line-height: 120%;
72 | }
73 | }
74 |
75 | @media (min-width: 600px) {
76 | .code {
77 | min-width: 50vw;
78 | max-width: 80vw;
79 | }
80 | }
81 |
82 | /* Overwrite the ugly standard prism styles */
83 | span[class~='token'] {
84 | background: none !important;
85 | }
86 |
87 | span[class~='comment'],
88 | span[class~='prolog'],
89 | span[class~='doctype'],
90 | span[class~='cdata'] {
91 | color: var(--color-gray-3) !important;
92 | }
93 |
94 | span[class~='tag'] {
95 | color: var(--color-gray-4) !important;
96 | }
97 |
98 | span[class~='punctuation'] {
99 | color: var(--color-gray-5) !important;
100 | }
101 |
102 | span[class~='operator'],
103 | span[class~='boolean'],
104 | span[class~='number'],
105 | span[class~='attr-name'] {
106 | color: var(--color-orange) !important;
107 | }
108 |
109 | span[class~='property'] {
110 | color: var(--color-yellow) !important;
111 | }
112 |
113 | span[class~='string'],
114 | span[class~='entity'],
115 | span[class~='url'],
116 | span[class~='statement'],
117 | span[class~='regex'],
118 | span[class~='atrule'] {
119 | color: var(--color-teal) !important;
120 | }
121 |
122 | span[class~='selector'] {
123 | color: var(--color-pink) !important;
124 | }
125 |
126 | span[class~='attr']-value,
127 | span[class~='keyword'],
128 | span[class~='control'],
129 | span[class~='directive'],
130 | span[class~='unit'] {
131 | color: var(--color-green) !important;
132 | }
133 |
134 | span[class~='placeholder'],
135 | span[class~='variable'],
136 | span[class~='function'] {
137 | color: var(--color-blue) !important;
138 | }
139 |
140 | span[class~='important'] {
141 | color: var(--color-red) !important;
142 | }
143 |
--------------------------------------------------------------------------------
/src/components/PresenterNotes.js:
--------------------------------------------------------------------------------
1 | import React, { Component, cloneElement } from 'react';
2 | import { renderToString } from 'react-dom/server';
3 | import PropTypes from 'prop-types';
4 |
5 | import style from './PresenterNotes.css';
6 |
7 | export default class PresenterNotes extends Component {
8 | /* eslint-disable react/no-unused-prop-types */
9 | static propTypes = {
10 | notes: PropTypes.string,
11 | slide: PropTypes.node.isRequired,
12 | next: PropTypes.node,
13 | parentStyles: PropTypes.objectOf(PropTypes.any),
14 | origin: PropTypes.string.isRequired,
15 | };
16 | /* eslint-enable react/no-unused-prop-types */
17 |
18 | static defaultProps = {
19 | notes: undefined,
20 | next: undefined,
21 | parentStyles: PropTypes.shape({}),
22 | };
23 |
24 | constructor(props) {
25 | super(props);
26 |
27 | this.state = { timerTotal: 0, timer: '00:00:00', ...this.props };
28 | this.updateTimer = ::this.updateTimer;
29 | }
30 |
31 | componentDidMount() {
32 | window.setInterval(this.updateTimer, 1000);
33 | }
34 |
35 | injectOrigin(htmlString) {
36 | const { origin } = this.props;
37 | return htmlString.replace(/src="([^"]*)"/gi, (match, media) => `src="${origin}${media}"`);
38 | }
39 |
40 | updateTimer() {
41 | const { timerTotal } = this.state;
42 | const pad = toPad => (`${toPad}`.length > 1 ? `${toPad}` : `0${toPad}`);
43 |
44 | this.setState(state => ({
45 | ...state,
46 | timerTotal: timerTotal + 1,
47 | timer: `${pad(parseInt(timerTotal / 3600, 10))}:${pad(parseInt(timerTotal / 60, 10))}:${pad(
48 | timerTotal % 60,
49 | )}`,
50 | }));
51 | }
52 |
53 | renderIframe(title, content) {
54 | const { parentStyles } = this.props;
55 |
56 | return (
57 |