├── test ├── e2e.spec.js ├── setup.ts ├── .eslintrc ├── reducers │ └── slides │ │ ├── actions │ │ ├── openFile-spec.ts │ │ ├── openNewDeck-spec.ts │ │ ├── moveSlideUp-spec.ts │ │ ├── moveSlideDown-spec.ts │ │ ├── duplicateSlide-spec.ts │ │ ├── deleteSlide-spec.ts │ │ ├── addPluginToCurrentSlide-spec.ts │ │ ├── deleteCurrentPlugin-spec.ts │ │ ├── updateCurrentPlugin-spec.ts │ │ └── addSlide-spec.ts │ │ └── slidesReducer.spec.ts └── components │ ├── ControlPanel.spec.tsx │ └── SmartSlide-spec.tsx ├── app ├── theme │ ├── _mixins.scss │ ├── _variables.scss │ ├── toolbar.scss │ ├── mixins │ │ └── _toolbar.scss │ ├── _reset.scss │ ├── _global.scss │ └── _utils.scss ├── modules │ ├── App │ │ ├── EditView │ │ │ ├── SettingsMenu │ │ │ │ ├── settings-menu.scss │ │ │ │ └── SettingsMenu.tsx │ │ │ ├── edit-view.scss │ │ │ └── EditView.tsx │ │ ├── FullscreenView │ │ │ ├── fullscreen-view.scss │ │ │ └── FullscreenView.tsx │ │ └── App.tsx │ ├── ToolBar │ │ ├── toolbar.scss │ │ └── ToolBar.tsx │ ├── ControlPanel │ │ ├── control-panel.scss │ │ └── ControlPanel.tsx │ ├── UtilitiesMenu │ │ ├── DefaultOptions │ │ │ ├── options.scss │ │ │ ├── Options │ │ │ │ ├── DuplicateSlide.tsx │ │ │ │ ├── MoveSlide.tsx │ │ │ │ ├── BackgroundColor.tsx │ │ │ │ └── SelectTransitions.tsx │ │ │ └── DefaultOptions.tsx │ │ ├── utilities-menu.scss │ │ └── UtilitiesMenu.tsx │ ├── SmartSlide │ │ ├── smart-slide.scss │ │ └── SmartSlide.tsx │ ├── index.ts │ ├── Scale │ │ └── Scale.tsx │ ├── MiniSlidesPanel │ │ ├── mini-slide-panel.scss │ │ └── MiniSlidesPanel.tsx │ └── DummySlide │ │ └── DummySlide.tsx ├── app.icns ├── constants │ ├── slides.enums.ts │ ├── app.constants.ts │ └── slides.constants.ts ├── reducers │ ├── index.ts │ ├── slides.reducer.ts │ └── app.reducer.ts ├── plugins │ └── node_modules │ │ ├── devdecks-textbox │ │ ├── fonts │ │ │ ├── Coda.ttf │ │ │ ├── Exo.ttf │ │ │ ├── Hind.ttf │ │ │ ├── Lobster.ttf │ │ │ ├── Oxygen.ttf │ │ │ ├── Raleway.ttf │ │ │ ├── Roboto.ttf │ │ │ ├── Satisfy.ttf │ │ │ ├── Ubuntu.ttf │ │ │ ├── Droid Sans.ttf │ │ │ ├── Orbitron.ttf │ │ │ ├── Tangerine.ttf │ │ │ ├── Electrolize.ttf │ │ │ └── _index.scss │ │ ├── text-box.scss │ │ ├── index.ts │ │ ├── options │ │ │ ├── FontSize.tsx │ │ │ ├── FontFamily.tsx │ │ │ ├── Utils.tsx │ │ │ ├── FontColor.tsx │ │ │ ├── FontBackgroundColor.tsx │ │ │ └── FontStyles.tsx │ │ ├── TextBox.tsx │ │ └── OptionsMenu.tsx │ │ ├── devdecks-image │ │ ├── add-image.scss │ │ ├── index.ts │ │ ├── AddImageDialog.tsx │ │ ├── OptionsMenu.tsx │ │ └── AddImage.tsx │ │ └── devdecks-code-editor │ │ ├── Options │ │ ├── lanuages.ts │ │ ├── ToggleConsole.tsx │ │ ├── CodeRun.tsx │ │ ├── CodeLang.tsx │ │ ├── CodeTheme.tsx │ │ ├── CodeImportExport.tsx │ │ ├── CodeEdit.tsx │ │ └── CodeHighlightSubmit.tsx │ │ ├── index.ts │ │ ├── code-editor.scss │ │ ├── OptionsMenu.tsx │ │ └── CodeEditor.tsx ├── app.global.scss ├── store │ ├── configureStore.js │ ├── configureStore.production.js │ ├── reducers.js │ └── configureStore.development.js ├── index.tsx ├── utils │ └── requireContext.ts ├── package.json ├── app.html ├── actions │ ├── app.actions.ts │ └── slides.actions.ts └── main.development.js ├── .gitattributes ├── resources ├── icon.icns ├── icon.ico ├── icon.png └── icons │ ├── 128x128.png │ ├── 16x16.png │ ├── 24x24.png │ ├── 256x256.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 512x512.png │ ├── 64x64.png │ ├── 96x96.png │ └── 1024x1024.png ├── webpack.config.eslint.js ├── docs ├── README.md ├── Create_Plugin.md ├── API.md └── Example.md ├── .travis.yml ├── tslint.json ├── webpack.config.test.js ├── tsconfig.json ├── .babelrc ├── .gitignore ├── .eslintrc ├── LICENSE ├── server.js ├── webpack.config.electron.js ├── webpack.config.base.js ├── webpack.config.production.js ├── webpack.config.development.js ├── README.md └── package.json /test/e2e.spec.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/theme/_mixins.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/theme/_variables.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/theme/toolbar.scss: -------------------------------------------------------------------------------- 1 | @import './mixins/_toolbar'; -------------------------------------------------------------------------------- /app/modules/App/EditView/SettingsMenu/settings-menu.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/app.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/app.icns -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # * text eol=lf 2 | *.png binary 3 | *.ico binary 4 | *.icns binary 5 | -------------------------------------------------------------------------------- /app/constants/slides.enums.ts: -------------------------------------------------------------------------------- 1 | export enum EDirection { 2 | RIGHT, 3 | LEFT, 4 | } 5 | -------------------------------------------------------------------------------- /resources/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icon.icns -------------------------------------------------------------------------------- /resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icon.ico -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icon.png -------------------------------------------------------------------------------- /app/reducers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app.reducer'; 2 | export * from './slides.reducer'; 3 | 4 | -------------------------------------------------------------------------------- /resources/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/128x128.png -------------------------------------------------------------------------------- /resources/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/16x16.png -------------------------------------------------------------------------------- /resources/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/24x24.png -------------------------------------------------------------------------------- /resources/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/256x256.png -------------------------------------------------------------------------------- /resources/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/32x32.png -------------------------------------------------------------------------------- /resources/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/48x48.png -------------------------------------------------------------------------------- /resources/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/512x512.png -------------------------------------------------------------------------------- /resources/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/64x64.png -------------------------------------------------------------------------------- /resources/icons/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/96x96.png -------------------------------------------------------------------------------- /resources/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/resources/icons/1024x1024.png -------------------------------------------------------------------------------- /app/modules/ToolBar/toolbar.scss: -------------------------------------------------------------------------------- 1 | @import '../../theme/toolbar.scss'; 2 | 3 | #toolbar { 4 | flex: 1 0 70%; 5 | } -------------------------------------------------------------------------------- /app/theme/mixins/_toolbar.scss: -------------------------------------------------------------------------------- 1 | @mixin toolbar-border { 2 | border: 1px #000 solid; 3 | border-radius: 0px; 4 | } -------------------------------------------------------------------------------- /webpack.config.eslint.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | 3 | module.exports = require('./webpack.config.development'); 4 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [Creating a plugin](Create_Plugin.md) 4 | * [API](API.md) 5 | * [Example](Example.md) -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Coda.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Coda.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Exo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Exo.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Hind.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Hind.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Lobster.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Lobster.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Oxygen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Oxygen.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Raleway.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Raleway.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Roboto.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Roboto.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Satisfy.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Satisfy.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Ubuntu.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Ubuntu.ttf -------------------------------------------------------------------------------- /app/app.global.scss: -------------------------------------------------------------------------------- 1 | @import './theme/_global'; 2 | @import './theme/_mixins'; 3 | @import './theme/_reset'; 4 | @import './theme/_variables'; 5 | @import './theme/_utils'; 6 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Droid Sans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Droid Sans.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Orbitron.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Orbitron.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Tangerine.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Tangerine.ttf -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/fonts/Electrolize.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Team-CHAD/DevDecks/HEAD/app/plugins/node_modules/devdecks-textbox/fonts/Electrolize.ttf -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 7 5 | - 6 6 | - "node" 7 | 8 | cache: 9 | directories: 10 | - node_modules 11 | 12 | script: 13 | - npm test 14 | - npm run package 15 | -------------------------------------------------------------------------------- /app/modules/App/FullscreenView/fullscreen-view.scss: -------------------------------------------------------------------------------- 1 | #fullscreen-view { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | height: 100vh; 6 | background-color: #000; 7 | overflow: hidden; 8 | } 9 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-image/add-image.scss: -------------------------------------------------------------------------------- 1 | #devdeck-add-image { 2 | #add-image-button { 3 | width: 100%; 4 | } 5 | 6 | .add-image-url { 7 | display: flex; 8 | justify-content: flex-start; 9 | } 10 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:latest", "tslint-react"], 3 | "rules": { 4 | "curly": true, 5 | "jsx-no-lambda": true, 6 | "no-var-requires": false 7 | }, 8 | "jsRules": { 9 | "curly": true 10 | } 11 | } -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/text-box.scss: -------------------------------------------------------------------------------- 1 | .devdecks-textbox-container { 2 | .editable-content-editable { 3 | outline: 0px solid transparent; 4 | } 5 | 6 | span, b, i, u { 7 | font-size: 1em !important; 8 | } 9 | } -------------------------------------------------------------------------------- /app/store/configureStore.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./configureStore.production'); // eslint-disable-line global-require 3 | } else { 4 | module.exports = require('./configureStore.development'); // eslint-disable-line global-require 5 | } 6 | -------------------------------------------------------------------------------- /app/store/configureStore.production.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import rootReducer from './reducers'; 3 | 4 | const enhancer = applyMiddleware(); 5 | 6 | export default function configureStore(initialState) { 7 | return createStore(rootReducer, initialState, enhancer); 8 | } 9 | -------------------------------------------------------------------------------- /app/store/reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | 3 | import { 4 | undoableAppReducer as app, 5 | undoableSlidesReducer as slides, 6 | } from '../reducers/index.ts'; 7 | 8 | const rootReducer = combineReducers({ 9 | app, 10 | slides, 11 | }); 12 | 13 | export default rootReducer; 14 | -------------------------------------------------------------------------------- /app/modules/ControlPanel/control-panel.scss: -------------------------------------------------------------------------------- 1 | #control-panel-container { 2 | width: 100%; 3 | background-color: #000; 4 | text-align: center; 5 | margin-bottom: 20px; 6 | padding: 6px 0; 7 | 8 | .pt-button { 9 | margin: 0 5px; 10 | opacity: 0.6; 11 | 12 | &:hover { 13 | opacity: 1.0; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /app/modules/UtilitiesMenu/DefaultOptions/options.scss: -------------------------------------------------------------------------------- 1 | #utilities-menu-default-options { 2 | #move-slide-container { 3 | display: flex; 4 | list-style-type: none; 5 | justify-content: center; 6 | 7 | li { 8 | margin: 0 5px; 9 | } 10 | } 11 | 12 | .sketch-picker { 13 | margin: 5px auto 0; 14 | } 15 | } -------------------------------------------------------------------------------- /app/modules/SmartSlide/smart-slide.scss: -------------------------------------------------------------------------------- 1 | #current-slide-view { 2 | height: calc(100vh - 200px); 3 | width: calc(100vw - 275px); 4 | border: 1px solid black; 5 | margin-right: 1em; 6 | } 7 | 8 | .rnd { 9 | &.editing { 10 | border: 1px solid #1baee1; 11 | } 12 | 13 | &.force-dynamic-height { 14 | height: 100% !important; 15 | } 16 | } -------------------------------------------------------------------------------- /app/modules/index.ts: -------------------------------------------------------------------------------- 1 | export * from './App/App'; 2 | export * from './ControlPanel/ControlPanel'; 3 | export * from './DummySlide/DummySlide'; 4 | export * from './MiniSlidesPanel/MiniSlidesPanel'; 5 | export * from './UtilitiesMenu/UtilitiesMenu'; 6 | export * from './Scale/Scale'; 7 | export * from './SmartSlide/SmartSlide'; 8 | export * from './ToolBar/ToolBar'; 9 | -------------------------------------------------------------------------------- /app/modules/UtilitiesMenu/utilities-menu.scss: -------------------------------------------------------------------------------- 1 | #utilities-menu-container { 2 | background-color: #293742; 3 | max-height: 100vh; 4 | overflow-x: hidden; 5 | overflow-y: auto; 6 | text-align: center; 7 | } 8 | 9 | #options-list { 10 | margin-left: 10px; 11 | margin-right: 10px; 12 | } 13 | 14 | #delete-button-devdecks { 15 | width: 100%; 16 | margin: 0 auto 15px; 17 | } -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-image/index.ts: -------------------------------------------------------------------------------- 1 | import Image from './AddImage'; 2 | import ImageOptions from './OptionsMenu'; 3 | 4 | export default { 5 | component: Image, 6 | icon: 'media', 7 | moduleName: 'devdecks-image', 8 | tooltip: 'Image', 9 | optionsMenuComponent: ImageOptions, 10 | state: { 11 | height: 200, 12 | lockAspectRatio: false, 13 | value: '', 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-code-editor/Options/lanuages.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | 'Clojure', 3 | 'CPP', 4 | 'CSS', 5 | 'Djanjo', 6 | 'Go', 7 | 'Haskell', 8 | 'HTMLBars', 9 | 'Java', 10 | 'JavaScript', 11 | 'JSON', 12 | 'LESS', 13 | 'ObjectiveC', 14 | 'Perl', 15 | 'PHP', 16 | 'Python', 17 | 'Ruby', 18 | 'Scala', 19 | 'SCSS', 20 | 'SQL', 21 | 'Swift', 22 | 'TypeScript', 23 | ]; 24 | -------------------------------------------------------------------------------- /app/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import './app.global.scss'; 5 | 6 | import { 7 | App 8 | } from './modules'; 9 | 10 | const configureStore = require('./store/configureStore'); 11 | const store = configureStore(); 12 | 13 | render( 14 | 15 | 16 | , 17 | document.getElementById('root') 18 | ); 19 | -------------------------------------------------------------------------------- /app/modules/Scale/Scale.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | interface ScaleProps { 4 | children?: any; 5 | isFullScreen: boolean; 6 | scale: number; 7 | } 8 | 9 | const Scale = ({ children, isFullScreen, scale }: ScaleProps) => { 10 | return ( 11 |
12 | { children } 13 |
14 | ); 15 | }; 16 | 17 | export { Scale }; 18 | -------------------------------------------------------------------------------- /test/setup.ts: -------------------------------------------------------------------------------- 1 | // Issue with Windows 10 pathing so types could not be set in tsconfig.json 2 | // so we need to specify absolute paths 3 | /// 4 | /// 5 | /// 6 | 7 | import { jsdom } from 'jsdom'; 8 | 9 | declare var global: any; 10 | 11 | global.document = jsdom(''); 12 | -------------------------------------------------------------------------------- /webpack.config.test.js: -------------------------------------------------------------------------------- 1 | /** Used in .babelrc for 'test' environment */ 2 | 3 | // for babel-plugin-webpack-loaders 4 | require('babel-register'); 5 | const validate = require('webpack-validator'); 6 | const devConfig = require('./webpack.config.development'); 7 | 8 | module.exports = validate({ 9 | output: { 10 | libraryTarget: 'commonjs2' 11 | }, 12 | module: { 13 | // Use base + development loaders, but exclude 'babel-loader' 14 | loaders: devConfig.module.loaders.slice(1) 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "baseUrl": "app", 5 | "experimentalDecorators": true, 6 | "jsx": "react", 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "noImplicitAny": true, 10 | "outDir": "./build/", 11 | "preserveConstEnums": true, 12 | "removeComments": true, 13 | "target": "ES6" 14 | }, 15 | "include": [ 16 | "app/**/*" 17 | ], 18 | "exclude": [ 19 | "node_modules", 20 | "app/plugins/**/*" 21 | ] 22 | } -------------------------------------------------------------------------------- /app/utils/requireContext.ts: -------------------------------------------------------------------------------- 1 | // Pre-load all of our plugins so we can dynamically require 2 | // them later. Use req instead of require when trying to 3 | // access those modules. 4 | 5 | // Fix: 6 | // ERROR in ./app/utils/requireContext.ts 7 | // (4,21): error TS2339: Property 'context' does not exist on type 'NodeRequire'. 8 | declare const require: any; 9 | 10 | const req = require.context('../plugins/node_modules', true); 11 | 12 | export default function(moduleName: string) { 13 | return req(`./${moduleName}/index`).default; 14 | } 15 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-code-editor/index.ts: -------------------------------------------------------------------------------- 1 | import CodeEditor from './CodeEditor'; 2 | import CodeEditorOptions from './OptionsMenu'; 3 | 4 | export default { 5 | component: CodeEditor, 6 | icon: 'code', 7 | moduleName: 'devdecks-code-editor', 8 | tooltip: 'Code Editor', 9 | optionsMenuComponent: CodeEditorOptions, 10 | state: { 11 | highlightedItems: [], 12 | language: 'JavaScript', 13 | showLineNumbers: true, 14 | snippet: '', 15 | theme: 'monokai', 16 | width: 1279, 17 | height: 600, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /app/theme/_reset.scss: -------------------------------------------------------------------------------- 1 | // blueprintjs 2 | ul, ol { 3 | margin: 0 !important; 4 | padding: 0 !important; 5 | } 6 | 7 | .pt-menu { 8 | min-width: 0 !important; 9 | padding: 0 !important; 10 | background: none !important; 11 | } 12 | 13 | .pt-large .pt-menu-item::before { 14 | margin: 0 5px !important; 15 | } 16 | 17 | .pt-transition-container { 18 | z-index: 100 !important; 19 | } 20 | 21 | .pt-popover-content { 22 | padding: 5px !important; 23 | } 24 | 25 | .pt-menu-item::before, .pt-menu-item::after { 26 | color: #ffe39f !important; 27 | } 28 | -------------------------------------------------------------------------------- /app/theme/_global.scss: -------------------------------------------------------------------------------- 1 | // Enforces the scrollbar view 2 | ::-webkit-scrollbar { 3 | -webkit-appearance: none; 4 | width: 10px; 5 | } 6 | ::-webkit-scrollbar-thumb { 7 | border-radius: 4px; 8 | background-color: rgba(0,0,0,.5); 9 | box-shadow: 0 0 1px rgba(255,255,255,.5); 10 | } 11 | 12 | * { 13 | background: transparent; 14 | box-sizing: border-box; 15 | margin: 0; 16 | padding: 0; 17 | } 18 | 19 | html, body { 20 | width: 100%; 21 | height: 100%; 22 | } 23 | 24 | a:link visited { 25 | border-color: black; 26 | } 27 | 28 | a:hover { 29 | border-width: 4px; 30 | } -------------------------------------------------------------------------------- /app/constants/app.constants.ts: -------------------------------------------------------------------------------- 1 | export const ADD_THEME_COLOR = 'ADD_THEME_COLOR'; 2 | export const GO_TO_SLIDE = 'GO_TO_SLIDE'; 3 | export const LEFT_ARROW_PREV = 'LEFT_ARROW_PREV'; 4 | export const RIGHT_ARROW_NEXT = 'RIGHT_ARROW_NEXT'; 5 | export const SAVE_LAST_SLIDE_DIMENSION = 'SAVE_LAST_SLIDE_DIMENSION'; 6 | export const SET_ACTIVE_PLUGIN = 'SET_ACTIVE_PLUGIN'; 7 | export const TOGGLE_FULLSCREEN = 'TOGGLE_FULLSCREEN'; 8 | export const TOGGLE_GUIDELINES = 'TOGGLE_GUIDELINES'; 9 | export const UPDATE_DEVICE_DIMENSION = 'UPDATE_DEVICE_DIMENSION'; 10 | export const UPDATE_SLIDES_DIMENSION = 'UPDATE_SLIDES_DIMENSION'; 11 | -------------------------------------------------------------------------------- /app/constants/slides.constants.ts: -------------------------------------------------------------------------------- 1 | export const ADD_PLUGIN_TO_CURRENT_SLIDE = 'ADD_PLUGIN_TO_CURRENT_SLIDE'; 2 | export const ADD_SLIDE = 'ADD_SLIDE'; 3 | export const DELETE_CURRENT_PLUGIN = 'DELETE_CURRENT_PLUGIN'; 4 | export const DELETE_SLIDE = 'DELETE_SLIDE'; 5 | export const DUPLICATE_SLIDE = 'DUPLICATE_SLIDE'; 6 | export const MOVE_SLIDE_DOWN = 'MOVE_SLIDE_DOWN'; 7 | export const MOVE_SLIDE_UP = 'MOVE_SLIDE_UP'; 8 | export const OPEN_FILE = 'OPEN_FILE'; 9 | export const OPEN_NEW_DECK = 'OPEN_NEW_DECK'; 10 | export const UPDATE_CURRENT_PLUGIN = 'UPDATE_CURRENT_PLUGIN'; 11 | export const UPDATE_CURRENT_SLIDE = 'UPDATE_CURRENT_SLIDE'; 12 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "plugins": [ 6 | "mocha" 7 | ], 8 | "rules": { 9 | "mocha/no-exclusive-tests": 2, 10 | "mocha/no-skipped-tests": 0, 11 | "mocha/no-pending-tests": 2, 12 | "mocha/handle-done-callback": 2, 13 | "mocha/no-synchronous-tests": 0, 14 | "mocha/no-global-tests": 2, 15 | "mocha/valid-test-description": 2, 16 | "mocha/valid-suite-description": 2, 17 | "mocha/no-sibling-hooks": 0, 18 | "mocha/no-mocha-arrows": 0, 19 | "mocha/no-hooks": 0, 20 | "mocha/no-top-level-hooks": 0, 21 | "no-unused-expressions": 0 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/reducers/slides/actions/openFile-spec.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import { expect } from 'chai'; 4 | import { OPEN_FILE } from '../../../../app/constants/slides.constants'; 5 | 6 | export default function(initialState: any, reducer: any, slide: any) { 7 | const file = fs.readFileSync(path.join(__dirname, '../test.dd')); 8 | describe('OPEN_FILE', () => { 9 | it('should set slide state to the new file', () => { 10 | const slides = JSON.parse(file.toString()); 11 | expect(reducer(initialState, { 12 | type: OPEN_FILE, 13 | buffer_data: file 14 | })).to.deep.equal(slides); 15 | }); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /app/modules/MiniSlidesPanel/mini-slide-panel.scss: -------------------------------------------------------------------------------- 1 | $mini-slides-padding: 10px 0px; 2 | $mini-slide-border: 2px solid #106BA3; 3 | 4 | #mini-slide-panel { 5 | list-style-type: none; 6 | overflow-y: auto; 7 | 8 | .mini-slide-item { 9 | padding: $mini-slides-padding; 10 | 11 | &.active { 12 | background-color: #5C7080; 13 | } 14 | } 15 | 16 | .mini-slide-content { 17 | position: relative; 18 | background-color: white; 19 | box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3); 20 | box-sizing: initial; 21 | margin: 0 auto; 22 | } 23 | 24 | .mini-slide-counter { 25 | float: left; 26 | font-weight: 600; 27 | margin-left: 5px; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/modules/UtilitiesMenu/DefaultOptions/Options/DuplicateSlide.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Button } from '@blueprintjs/core'; 3 | 4 | interface DuplicateSlideProps { 5 | currentSlideNumber: number; 6 | maxSlides: number; 7 | goToSlide: Function; 8 | duplicateSlide: Function; 9 | } 10 | 11 | const DuplicateSlide = ({ currentSlideNumber, maxSlides, duplicateSlide, goToSlide }: DuplicateSlideProps) => { 12 | return ( 13 | 35 |
36 | updateCurrentPlugin({ imageUrl: value })} /> 42 | 43 | ); 44 | } 45 | } 46 | 47 | export default OptionsMenu; 48 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/TextBox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import './text-box.scss'; 3 | 4 | const ContentEditable = require("react-contenteditable"); 5 | 6 | interface TextBoxProps { 7 | disabled: boolean; 8 | pluginState: any; 9 | updateCurrentPlugin: Function; 10 | } 11 | 12 | const TextBox = ({ disabled, pluginState, updateCurrentPlugin }: TextBoxProps) => { 13 | const { 14 | fontBackgroundColor, 15 | fontColor, 16 | fontSize, 17 | fontFamily, 18 | textAlignment, 19 | value, 20 | width, 21 | } = pluginState; 22 | 23 | return ( 24 |
33 | { 38 | if (!value) { 39 | updateCurrentPlugin({ 40 | isOrderedList: false, 41 | isUnorderedList: false, 42 | value: e.target.value, 43 | }); 44 | } else { 45 | updateCurrentPlugin({ value: e.target.value }); 46 | } 47 | }} 48 | /> 49 |
50 | ); 51 | } 52 | 53 | export default TextBox; 54 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/options/Utils.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Button, Intent } from "@blueprintjs/core"; 3 | 4 | interface UtilsProps { 5 | pluginState: any; 6 | updateCurrentPlugin: any; 7 | } 8 | 9 | const Utils = ({ pluginState, updateCurrentPlugin }: UtilsProps) => { 10 | const { isOrderedList, isUnorderedList } = pluginState; 11 | return ( 12 |
13 |
37 | ); 38 | }; 39 | 40 | export default Utils; 41 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-code-editor/Options/CodeImportExport.tsx: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as React from 'react'; 3 | import { remote } from 'electron'; 4 | import { Button } from '@blueprintjs/core'; 5 | 6 | interface CodeImportExportProps { 7 | pluginState: any; 8 | updateCurrentPlugin: Function; 9 | } 10 | 11 | const CodeImportExport = ({ pluginState, updateCurrentPlugin }: CodeImportExportProps) => { 12 | const { snippet } = pluginState; 13 | 14 | const selectCodeFileToImport: React.MouseEventHandler = () => { 15 | remote.dialog.showOpenDialog((filePaths: string[]) => { 16 | if (!filePaths) return; 17 | fs.readFile(filePaths[0], (err: any, data: any) => { 18 | if (err) return; 19 | updateCurrentPlugin({ snippet: data.toString() }); 20 | }); 21 | }); 22 | }; 23 | 24 | const selectCodeFileToExport: React.MouseEventHandler = () => { 25 | remote.dialog.showSaveDialog((filename: string) => { 26 | if (!filename) return; 27 | fs.writeFile(filename, snippet); 28 | }); 29 | }; 30 | 31 | return ( 32 |
  • 33 |
  • 43 | ); 44 | }; 45 | 46 | 47 | export default CodeImportExport; 48 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-textbox/options/FontColor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { SketchPicker } from 'react-color'; 3 | import { Button, Popover, PopoverInteractionKind, Position } from '@blueprintjs/core'; 4 | 5 | interface FontColor { 6 | pluginState: any; 7 | theme: any; 8 | addThemeColor: Function; 9 | updateCurrentPlugin: Function; 10 | } 11 | 12 | const FontColor = ({ pluginState, theme, addThemeColor, updateCurrentPlugin }: FontColor) => { 13 | const { fontBackgroundColor, fontColor, fontColorHex } = pluginState; 14 | const { colors } = theme; 15 | 16 | const content = ( 17 |
    18 | 23 | updateCurrentPlugin({ 24 | fontColor: `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.rgb.a})`, 25 | fontColorHex: color.hex 26 | })} /> 27 |
    35 | ); 36 | 37 | return ( 38 | 41 | 124 | 125 | ); 126 | }; 127 | 128 | export default ImageOptions; 129 | ``` 130 | 131 | ### devdecks-image.scss 132 | ```scss 133 | #devdecks-image-options-container { 134 | #add-image-button { 135 | width: 100%; 136 | } 137 | } 138 | ``` -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-code-editor/Options/CodeEdit.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Button, Dialog, Intent } from '@blueprintjs/core'; 3 | 4 | const brace = require('brace'); 5 | const AceEditor = require('react-ace').default; 6 | 7 | //languages 8 | require('brace/mode/c_cpp'); 9 | require('brace/mode/clojure'); 10 | require('brace/mode/css'); 11 | require('brace/mode/django'); 12 | require('brace/mode/golang'); 13 | require('brace/mode/haskell'); 14 | require('brace/mode/html'); 15 | require('brace/mode/java'); 16 | require('brace/mode/javascript'); 17 | require('brace/mode/json'); 18 | require('brace/mode/less'); 19 | require('brace/mode/objectivec'); 20 | require('brace/mode/perl'); 21 | require('brace/mode/php'); 22 | require('brace/mode/python'); 23 | require('brace/mode/ruby'); 24 | require('brace/mode/scala'); 25 | require('brace/mode/scss'); 26 | require('brace/mode/sql'); 27 | require('brace/mode/swift'); 28 | require('brace/mode/typescript'); 29 | 30 | //themes 31 | require('brace/theme/xcode'); 32 | 33 | interface CodeEditProps { 34 | pluginState: any; 35 | updateCurrentPlugin: Function; 36 | } 37 | 38 | interface CodeEditStates { 39 | value: string; 40 | } 41 | 42 | class CodeEdit extends React.Component { 43 | constructor() { 44 | super(); 45 | this.state = { 46 | value: '', 47 | }; 48 | } 49 | 50 | componentWillReceiveProps() { 51 | const { pluginState: { snippet } } = this.props; 52 | if (this.state.value !== snippet) { 53 | this.setState({ value: snippet }); 54 | } 55 | } 56 | 57 | render() { 58 | const { pluginState, updateCurrentPlugin } = this.props; 59 | const { value } = this.state; 60 | const { fontSize, isOpen, snippet, snippetEval, theme } = pluginState; 61 | 62 | let { language } = pluginState; 63 | switch (language) { 64 | case 'CPP': { 65 | language = 'c_cpp'; 66 | break; 67 | } 68 | case 'Go': { 69 | language = 'golang'; 70 | break; 71 | } 72 | case 'HTMLBars': { 73 | language = 'html'; 74 | break; 75 | } 76 | } 77 | 78 | return ( 79 |
  • 80 |
  • 118 | ); 119 | } 120 | } 121 | 122 | export default CodeEdit; 123 | -------------------------------------------------------------------------------- /app/reducers/slides.reducer.ts: -------------------------------------------------------------------------------- 1 | import * as constants from '../constants/slides.constants'; 2 | 3 | const cloneDeep = require('lodash.clonedeep'); 4 | const undoable = require('redux-undo').default; 5 | 6 | interface Slide { 7 | plugins: any[]; 8 | state: { 9 | backgroundColor: { 10 | r: number; 11 | g: number; 12 | b: number; 13 | a: number; 14 | }; 15 | transition: { 16 | right: string; 17 | left: string; 18 | }; 19 | }; 20 | } 21 | 22 | const initialSlideState: Slide = { 23 | plugins: [], 24 | state: { 25 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 26 | transition: { 27 | right: 'rotate-push-left-move-from-right', 28 | left: 'rotate-push-right-move-from-left', 29 | } 30 | } 31 | }; 32 | 33 | const initialSlidesState: Slide[] = [ initialSlideState ]; 34 | 35 | export const slidesReducer = (state: any = initialSlidesState, action: any) => { 36 | const slides = cloneDeep(state); 37 | 38 | switch (action.type) { 39 | case constants.ADD_PLUGIN_TO_CURRENT_SLIDE: { 40 | const { plugin, slideNumber } = action; 41 | slides[slideNumber].plugins.push(plugin); 42 | return slides; 43 | } 44 | 45 | case constants.ADD_SLIDE: { 46 | const newSlide = cloneDeep(initialSlideState); 47 | slides.splice(action.currentSlide + 1, 0, newSlide); 48 | return slides; 49 | } 50 | 51 | case constants.DELETE_CURRENT_PLUGIN: { 52 | const { pluginNumber, slideNumber } = action; 53 | slides[slideNumber].plugins[pluginNumber] = null; 54 | return slides; 55 | } 56 | 57 | case constants.DELETE_SLIDE: { 58 | slides.splice(action.slideToDelete, 1); 59 | return slides; 60 | } 61 | 62 | case constants.DUPLICATE_SLIDE: { 63 | const { slideToDuplicate } = action; 64 | const dupedSlide = cloneDeep(slides[slideToDuplicate]); 65 | slides.splice(slideToDuplicate + 1, 0, dupedSlide); 66 | return slides; 67 | } 68 | 69 | case constants.MOVE_SLIDE_DOWN: { 70 | const { slideNumber } = action; 71 | 72 | if (slideNumber === 0) return slides; 73 | 74 | const currentSlide = slides[slideNumber]; 75 | const previousSlide = slides[slideNumber - 1]; 76 | slides[slideNumber] = previousSlide; 77 | slides[slideNumber - 1] = currentSlide; 78 | 79 | return slides; 80 | } 81 | 82 | case constants.MOVE_SLIDE_UP: { 83 | const { slideNumber } = action; 84 | 85 | if (slideNumber >= state.length - 1) return slides; 86 | 87 | const currentSlide = slides[slideNumber]; 88 | const nextSlide = slides[slideNumber + 1]; 89 | slides[slideNumber] = nextSlide; 90 | slides[slideNumber + 1] = currentSlide; 91 | 92 | return slides; 93 | } 94 | 95 | case constants.OPEN_FILE: { 96 | const { buffer_data } = action; 97 | const slidesFromFile = JSON.parse(buffer_data.toString()); 98 | return slidesFromFile; 99 | } 100 | 101 | case constants.OPEN_NEW_DECK: { 102 | const slides = initialSlidesState; 103 | return slides; 104 | } 105 | 106 | case constants.UPDATE_CURRENT_PLUGIN: { 107 | const { changes, pluginNumber, slideNumber } = action; 108 | const plugin = slides[slideNumber].plugins[pluginNumber]; 109 | 110 | for (const change in changes) { 111 | plugin.state[change] = changes[change]; 112 | } 113 | 114 | return slides; 115 | } 116 | 117 | case constants.UPDATE_CURRENT_SLIDE: { 118 | const { changes, slideNumber } = action; 119 | const slide = slides[slideNumber]; 120 | 121 | for (const change in changes) { 122 | slide.state[change] = changes[change]; 123 | } 124 | 125 | return slides; 126 | } 127 | 128 | default: { 129 | return state; 130 | } 131 | } 132 | } 133 | 134 | const undoableSlidesReducer = undoable(slidesReducer, { 135 | filter: function filterActions(action: any, currentState: any, previousHistory: any) { 136 | return true; 137 | } 138 | }); 139 | 140 | export { undoableSlidesReducer }; 141 | -------------------------------------------------------------------------------- /app/reducers/app.reducer.ts: -------------------------------------------------------------------------------- 1 | import { remote } from 'electron'; 2 | import * as constants from 'constants/app.constants'; 3 | import { EDirection }from 'constants/slides.enums'; 4 | 5 | const cloneDeep = require('lodash.clonedeep'); 6 | const undoable = require('redux-undo').default; 7 | 8 | interface IDimensions { 9 | width: number; 10 | height: number; 11 | } 12 | 13 | interface InitialAppState { 14 | deviceDimension: IDimensions; 15 | currentSlide: number; 16 | currentSelectedPlugin: any; 17 | isDragging: boolean; 18 | isFullScreen: boolean; 19 | lastSavedSlideDimensions: IDimensions; 20 | direction: EDirection; 21 | slidesDimension: IDimensions; 22 | theme: { 23 | colors: string[]; 24 | }; 25 | } 26 | 27 | const deviceDimension = { 28 | width: 1280, 29 | height: 800 30 | }; 31 | 32 | const initialAppState: InitialAppState = { 33 | deviceDimension, 34 | currentSlide: 0, 35 | currentSelectedPlugin: null, 36 | isDragging: false, 37 | isFullScreen: false, 38 | lastSavedSlideDimensions: deviceDimension, 39 | direction: EDirection.RIGHT, 40 | slidesDimension: { 41 | width: deviceDimension.width * .75, 42 | height: deviceDimension.height * .75 43 | }, 44 | theme: { 45 | colors: ['#ffeb3b', '#0062A3'], 46 | } 47 | }; 48 | 49 | const appReducer = (state: any = initialAppState, action: any) => { 50 | switch (action.type) { 51 | case constants.ADD_THEME_COLOR: { 52 | const { color } = action; 53 | 54 | const newState = cloneDeep(state); 55 | newState.theme.colors.push(color); 56 | 57 | return newState; 58 | } 59 | 60 | case constants.GO_TO_SLIDE: { 61 | const { maxSlides, slideNumber } = action; 62 | if (slideNumber < 1) return Object.assign({}, state, { 63 | currentSelectedPlugin: null, 64 | currentSlide: 0, 65 | }); 66 | if (slideNumber >= maxSlides) return state; 67 | return Object.assign({}, state, { 68 | currentSelectedPlugin: null, 69 | currentSlide: slideNumber, 70 | }); 71 | } 72 | 73 | case constants.LEFT_ARROW_PREV: { 74 | const currentSlide: number = state.currentSlide - 1; 75 | return Object.assign({}, state, { 76 | currentSlide, 77 | direction: EDirection.LEFT 78 | }); 79 | } 80 | 81 | case constants.RIGHT_ARROW_NEXT: { 82 | const currentSlide: number = state.currentSlide + 1; 83 | return Object.assign({}, state, { 84 | currentSlide, 85 | direction: EDirection.RIGHT 86 | }); 87 | } 88 | 89 | case constants.SAVE_LAST_SLIDE_DIMENSION: { 90 | const slideElement = document.getElementById('edit-slide-view'); 91 | const { clientWidth: width, clientHeight: height } = slideElement; 92 | return Object.assign({}, state, { lastSavedSlideDimensions: { width, height } }); 93 | } 94 | 95 | case constants.SET_ACTIVE_PLUGIN: { 96 | return Object.assign({}, state, { currentSelectedPlugin: action.newActivePlugin }); 97 | } 98 | 99 | case constants.TOGGLE_FULLSCREEN: { 100 | const window = remote.getCurrentWindow(); 101 | if (state.isFullScreen) { 102 | window.setMenuBarVisibility(true); 103 | window.setFullScreen(false) 104 | } else { 105 | window.setMenuBarVisibility(false); 106 | window.setFullScreen(true); 107 | } 108 | 109 | return Object.assign({}, state, { isFullScreen: !state.isFullScreen }); 110 | } 111 | 112 | case constants.TOGGLE_GUIDELINES: { 113 | return Object.assign({}, state, { isDragging: !state.isDragging }); 114 | } 115 | 116 | case constants.UPDATE_DEVICE_DIMENSION: { 117 | return Object.assign({}, state, { deviceDimension: action.newDeviceDimension }); 118 | } 119 | 120 | case constants.UPDATE_SLIDES_DIMENSION: { 121 | return Object.assign({}, state, { slidesDimension: action.slidesDimension }) 122 | } 123 | 124 | default: { 125 | return state; 126 | } 127 | } 128 | }; 129 | 130 | const ignoreActions:any = [constants.TOGGLE_GUIDELINES]; 131 | const undoableAppReducer = undoable(appReducer, { 132 | filter: function filterActions(action: any, currentState: any, previousHistory: any) { 133 | if (action.type === 'SET_ACTIVE_PLUGIN' || action.type === 'GO_TO_SLIDE') return true; 134 | return false; 135 | } 136 | }); 137 | 138 | export { undoableAppReducer }; 139 | -------------------------------------------------------------------------------- /test/reducers/slides/actions/addSlide-spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { ADD_SLIDE } from '../../../../app/constants/slides.constants'; 3 | 4 | export default function(initialState: any, reducer: any, slide: any) { 5 | describe('ADD_SLIDE', () => { 6 | it('should add a new slide at position 1 when current slide is 0 and there is only one slide', () => { 7 | const _initialState: any = [{ 8 | plugins: ['plugin1'], 9 | state: { 10 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 11 | transition: { 12 | right: 'rotate-push-left-move-from-right', 13 | left: 'rotate-push-right-move-from-left', 14 | } 15 | } 16 | }]; 17 | 18 | expect( 19 | reducer(_initialState, { 20 | type: ADD_SLIDE, 21 | currentSlide: 0 22 | }) 23 | ).to.deep.equal([ 24 | { 25 | plugins: ['plugin1'], 26 | state: { 27 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 28 | transition: { 29 | right: 'rotate-push-left-move-from-right', 30 | left: 'rotate-push-right-move-from-left', 31 | } 32 | } 33 | }, 34 | slide 35 | ]) 36 | .and.to.have.lengthOf(2); 37 | }); 38 | 39 | it('should add a new slide at position 2 when current slide is 1 and there are three slides', () => { 40 | const _initialState: any = [{ 41 | plugins: ['plugin1'], 42 | state: { 43 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 44 | transition: { 45 | right: 'rotate-push-left-move-from-right', 46 | left: 'rotate-push-right-move-from-left', 47 | } 48 | } 49 | }, { 50 | plugins: ['plugin1', 'plugin2'], 51 | state: { 52 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 53 | transition: { 54 | right: 'rotate-push-left-move-from-right', 55 | left: 'rotate-push-right-move-from-left', 56 | } 57 | } 58 | }, { 59 | plugins: ['plugin1', 'plugin2', 'plugin5'], 60 | state: { 61 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 62 | transition: { 63 | right: 'rotate-push-left-move-from-right', 64 | left: 'rotate-push-right-move-from-left', 65 | } 66 | } 67 | }]; 68 | 69 | expect( 70 | reducer(_initialState, { 71 | type: ADD_SLIDE, 72 | currentSlide: 1 73 | }) 74 | ) 75 | .to.deep.equal([ 76 | { 77 | plugins: ['plugin1'], 78 | state: { 79 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 80 | transition: { 81 | right: 'rotate-push-left-move-from-right', 82 | left: 'rotate-push-right-move-from-left', 83 | } 84 | } 85 | }, { 86 | plugins: ['plugin1', 'plugin2'], 87 | state: { 88 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 89 | transition: { 90 | right: 'rotate-push-left-move-from-right', 91 | left: 'rotate-push-right-move-from-left', 92 | } 93 | } 94 | }, slide, { 95 | plugins: ['plugin1', 'plugin2', 'plugin5'], 96 | state: { 97 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 98 | transition: { 99 | right: 'rotate-push-left-move-from-right', 100 | left: 'rotate-push-right-move-from-left', 101 | } 102 | } 103 | } 104 | ]) 105 | .and.to.have.lengthOf(4); 106 | }); 107 | 108 | it('should add a new slide at the end when last slide is selected', () => { 109 | const _initialState: any = [{ 110 | plugins: ['plugin1', 'plugin2'], 111 | state: { 112 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 113 | transition: { 114 | right: 'rotate-push-left-move-from-right', 115 | left: 'rotate-push-right-move-from-left', 116 | } 117 | } 118 | }, { 119 | plugins: ['plugin1', 'plugin2'], 120 | state: { 121 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 122 | transition: { 123 | right: 'rotate-push-left-move-from-right', 124 | left: 'rotate-push-right-move-from-left', 125 | } 126 | } 127 | }]; 128 | 129 | expect( 130 | reducer(_initialState, { 131 | type: ADD_SLIDE, 132 | currentSlide: 1 133 | }) 134 | ) 135 | .to.deep.equal([ 136 | { 137 | plugins: ['plugin1', 'plugin2'], 138 | state: { 139 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 140 | transition: { 141 | right: 'rotate-push-left-move-from-right', 142 | left: 'rotate-push-right-move-from-left', 143 | } 144 | } 145 | }, 146 | { 147 | plugins: ['plugin1', 'plugin2'], 148 | state: { 149 | backgroundColor: { r: 255, g: 255, b: 255, a: 100 }, 150 | transition: { 151 | right: 'rotate-push-left-move-from-right', 152 | left: 'rotate-push-right-move-from-left', 153 | } 154 | } 155 | }, 156 | slide 157 | ]) 158 | .and.to.have.lengthOf(3) 159 | }); 160 | }); 161 | } 162 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-code-editor/CodeEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import CodeRun from './Options/CodeRun'; 3 | import './code-editor.scss'; 4 | 5 | import { 6 | Popover, 7 | Position, 8 | } from '@blueprintjs/core'; 9 | 10 | const classNames = require('classnames'); 11 | const Highlight = require('react-highlight'); 12 | require('highlight.js/styles/xcode.css'); 13 | 14 | interface CodeEditorProps { 15 | isFullscreen?: boolean; 16 | pluginState: any; 17 | updateCurrentPlugin?: any; 18 | } 19 | 20 | class CodeEditor extends React.Component { 21 | codeBlocks: any[] = []; 22 | 23 | constructor() { 24 | super(); 25 | this.handleCodeHighlight = this.handleCodeHighlight.bind(this); 26 | this.state = { 27 | activeItem: 0, 28 | }; 29 | } 30 | 31 | private handleCodeHighlight(e: any) { 32 | const { pluginState: { highlightedItems } } = this.props; 33 | const { activeItem } = this.state; 34 | switch (e.keyCode) { 35 | // UP 36 | case 38: { 37 | if (activeItem > 0) this.setState({ activeItem: activeItem - 1 }); 38 | break; 39 | } 40 | 41 | // DOWN 42 | case 40: { 43 | if (activeItem < highlightedItems.length - 1) this.setState({ activeItem: activeItem + 1 }); 44 | break; 45 | } 46 | } 47 | }; 48 | 49 | public componentDidUpdate() { 50 | const { codeBlocks } = this; 51 | const { pluginState: { highlightedItems } } = this.props; 52 | const { activeItem } = this.state; 53 | const activeBlock = highlightedItems[activeItem]; 54 | if (activeBlock) { 55 | const scrollToCodeBlock = codeBlocks[activeBlock.start] 56 | scrollToCodeBlock ? scrollToCodeBlock.scrollIntoViewIfNeeded(true) : null; 57 | } 58 | } 59 | 60 | public render() { 61 | const { 62 | isFullscreen, 63 | pluginState, 64 | updateCurrentPlugin, 65 | } = this.props; 66 | 67 | const { activeItem } = this.state; 68 | 69 | const { 70 | fontSize, 71 | height, 72 | highlightedItems, 73 | isOpen, 74 | language, 75 | showLineNumbers, 76 | snippet, 77 | theme 78 | } = pluginState; 79 | 80 | const codeLineNumberClass = classNames({ 81 | 'code-line-number': true, 82 | 'show': !isFullscreen || showLineNumbers, 83 | }); 84 | 85 | const activeBlock = highlightedItems[activeItem]; 86 | const code = ( 87 | snippet.split('\n').map((line: string, i: number) => { 88 | if (!activeBlock){ 89 | return ( 90 |
    94 | {i} 95 | 96 | {line} 97 | 98 |
    99 | ); 100 | } else if (i >= activeBlock.start && i <= activeBlock.end) { 101 | if (i == activeBlock.end) { 102 | return ( 103 | 110 |
    this.codeBlocks[i] = c} 112 | className="code" 113 | id={`code-highlight-${i}`} > 114 | {i} 115 | 116 | {line} 117 | 118 |
    119 |
    120 | ); 121 | } 122 | 123 | return ( 124 |
    this.codeBlocks[i] = c} 126 | key={i} 127 | className="code" 128 | id={`code-highlight-${i}`} > 129 | {i} 130 | 131 | {line} 132 | 133 |
    134 | ); 135 | } 136 | return ( 137 |
    141 | {i} 142 | 143 | {line} 144 | 145 |
    146 | ); 147 | }) 148 | ); 149 | 150 | return ( 151 |
    {} } 156 | onKeyDown={this.handleCodeHighlight} > 157 | { 158 | snippet 159 | ?
    160 | {code} 161 | { 162 | isFullscreen 163 | ? 166 | : null 167 | } 168 |
    169 | : 172 | 173 | } 174 |
    175 | ); 176 | } 177 | } 178 | 179 | export default CodeEditor; 180 | -------------------------------------------------------------------------------- /app/plugins/node_modules/devdecks-code-editor/Options/CodeHighlightSubmit.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { 4 | Alert, 5 | Button, 6 | Intent, 7 | Tag, 8 | } from '@blueprintjs/core'; 9 | 10 | const cloneDeep = require('lodash.clonedeep'); 11 | 12 | const { SortableContainer, SortableElement, arrayMove } = require('react-sortable-hoc'); 13 | 14 | const SortableItem = SortableElement((props: any) => { 15 | const { highlightedItems, position, value, updateCurrentPlugin } = props; 16 | return ( 17 |
  • 18 | { 20 | const _highlightedItems = cloneDeep(highlightedItems); 21 | _highlightedItems.splice(position, 1); 22 | updateCurrentPlugin({ highlightedItems: _highlightedItems }); 23 | }}> 24 | {value} 25 | 26 |
  • 27 | ); 28 | }); 29 | 30 | const SortableList = SortableContainer((props: any) => { 31 | const { highlightedItems, updateCurrentPlugin } = props; 32 | return ( 33 |
      34 | { 35 | props.items.map((value: any, index: number) => 36 | 43 | ) 44 | } 45 |
    46 | ); 47 | }); 48 | 49 | interface CodeHighlightSubmitProps { 50 | pluginState: any; 51 | updateCurrentPlugin: Function; 52 | } 53 | 54 | interface CodeHighlightSubmitStates { 55 | alertMessage?: string; 56 | isAlert?: boolean; 57 | start?: string; 58 | end?: string; 59 | text?: string; 60 | } 61 | 62 | class CodeHighlightSubmit extends React.Component { 63 | maxLines: number = 0; 64 | 65 | constructor() { 66 | super(); 67 | this.handleSort = this.handleSort.bind(this); 68 | this.validateHighlightBlock = this.validateHighlightBlock.bind(this); 69 | this.state = { 70 | alertMessage: '', 71 | isAlert: false, 72 | start: '', 73 | end: '', 74 | text: '', 75 | }; 76 | } 77 | 78 | private handleSort({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) { 79 | const { pluginState: { highlightedItems }, updateCurrentPlugin } = this.props; 80 | updateCurrentPlugin({ highlightedItems: arrayMove(highlightedItems, oldIndex, newIndex) }); 81 | } 82 | 83 | private validateHighlightBlock() { 84 | const { pluginState: { highlightedItems, snippet } } = this.props; 85 | const { start, end, text } = this.state; 86 | 87 | const max = snippet.split('\n').length - 1; 88 | if (!start || +start < 0 || +start > max) { 89 | return { 90 | success: false, 91 | message: 'Start value cannot be less than 0 or greater than number of lines', 92 | }; 93 | } 94 | if (!end || +end < +start || +end > max) { 95 | return { 96 | success: false, 97 | message: 'End value cannot be less than start value or greater than number of lines', 98 | }; 99 | } 100 | return { 101 | success: true, 102 | }; 103 | } 104 | 105 | public componentWillReceiveProps(nextProps: CodeHighlightSubmitProps) { 106 | const { snippet } = nextProps.pluginState; 107 | this.maxLines = snippet.split('\n').length - 1; 108 | } 109 | 110 | public render() { 111 | const { pluginState: { highlightedItems, snippet }, updateCurrentPlugin } = this.props; 112 | const disabled = snippet ? false : true; 113 | const items = highlightedItems.map((highlightedItem: any) => `${highlightedItem.start}-${highlightedItem.end}`); 114 | 115 | return ( 116 |
    117 | this.setState({ isAlert: false })}> 122 | {this.state.alertMessage} 123 | 124 | 125 |
    126 | this.setState({ start: e.target.value })}/> 135 | - 136 | this.setState({ end: e.target.value })} /> 145 |
    146 |