├── .editorconfig ├── .gitignore ├── .npmignore ├── .prettierrc ├── Dockerfile ├── LICENSE ├── README.md ├── _config.yml ├── cli ├── index.cli.js └── updatesInfo.js ├── commitlint.config.js ├── docs ├── cc-ui-3.png ├── dep-ui-2.png ├── dev.png ├── flow-ui.png ├── ide-integration.gif ├── live-changes.gif ├── logo-sm.png ├── main-ui-3.png └── multi-codebase-cc-2.png ├── example-project ├── codecrumbs.config.js ├── debug │ ├── index.js │ ├── sections │ │ ├── one.js │ │ └── two.js │ ├── utils │ │ └── changeListener │ │ │ └── behaviour.js │ ├── x1 │ │ └── index.js │ └── x2 │ │ ├── ok │ │ └── ok.js │ │ └── x │ │ └── index.js ├── languages │ ├── cpp-lang.cpp │ ├── csharp-lang.cs │ ├── fortran-lang.f │ ├── go-lang.go │ ├── haskell-lang.hs │ ├── java-lang.java │ ├── js-lang.js │ ├── kotlin-lang.kt │ ├── lua-lang.lua │ ├── ocaml.ml │ ├── perl-lang.pl │ ├── php-lang.php │ ├── python-lang.py │ ├── ruby-lang.rb │ └── ts-lang.ts ├── src-client │ ├── auth │ │ ├── action-types.js │ │ ├── actions.js │ │ ├── auth.js │ │ ├── index.js │ │ ├── reducer.js │ │ └── selectors.js │ ├── firebase │ │ ├── config.js │ │ ├── firebase-list.js │ │ ├── firebase.js │ │ └── index.js │ ├── history.js │ ├── index.js │ ├── notification │ │ ├── action-types.js │ │ ├── actions.js │ │ ├── index.js │ │ ├── reducer.js │ │ └── selectors.js │ ├── reducers.js │ ├── store.js │ ├── tasks │ │ ├── action-types.js │ │ ├── actions.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── selectors.js │ │ ├── task-list.js │ │ └── task.js │ ├── test_tml.vue │ ├── utils │ │ ├── create-test-component.js │ │ └── register-service-worker.js │ └── views │ │ ├── app │ │ ├── app.js │ │ └── index.js │ │ ├── components │ │ ├── button │ │ │ ├── button.js │ │ │ ├── button.scss │ │ │ └── index.js │ │ ├── github-logo │ │ │ ├── github-logo.js │ │ │ └── index.js │ │ ├── header │ │ │ ├── header.js │ │ │ ├── header.scss │ │ │ └── index.js │ │ ├── icon │ │ │ ├── icon.js │ │ │ └── index.js │ │ ├── notification │ │ │ ├── index.js │ │ │ ├── notification.js │ │ │ └── notification.scss │ │ ├── require-auth-route │ │ │ ├── index.js │ │ │ └── require-auth-route.js │ │ ├── require-unauth-route │ │ │ ├── index.js │ │ │ └── require-unauth-route.js │ │ ├── task-filters │ │ │ ├── index.js │ │ │ ├── task-filters.js │ │ │ └── task-filters.scss │ │ ├── task-form │ │ │ ├── index.js │ │ │ ├── task-form.js │ │ │ └── task-form.scss │ │ ├── task-item │ │ │ ├── index.js │ │ │ ├── task-item.js │ │ │ └── task-item.scss │ │ └── task-list │ │ │ ├── index.js │ │ │ ├── task-list.js │ │ │ └── task-list.scss │ │ ├── pages │ │ ├── sign-in │ │ │ ├── index.js │ │ │ ├── sign-in-page.js │ │ │ └── sign-in-page.scss │ │ └── tasks │ │ │ ├── index.js │ │ │ └── tasks-page.js │ │ └── styles │ │ ├── _grid.scss │ │ ├── _settings.scss │ │ ├── _shared.scss │ │ └── styles.scss ├── src-php │ ├── Http │ │ ├── Controllers │ │ │ ├── CommentController.php │ │ │ └── PostController.php │ │ └── Requests │ │ │ └── PostRequest.php │ ├── Models │ │ ├── Category.php │ │ └── Post.php │ └── index.php ├── src-server │ ├── app │ │ ├── models │ │ │ └── todo.py │ │ ├── routes.py │ │ └── service │ │ │ ├── auth │ │ │ └── signin.py │ │ │ └── user │ │ │ └── session.py │ ├── config │ │ └── database.py │ └── index.py ├── src-typescript │ ├── app.tsx │ ├── components │ │ ├── about.tsx │ │ ├── header.tsx │ │ ├── index.ts │ │ └── login │ │ │ ├── index.ts │ │ │ ├── loginForm.styles.ts │ │ │ ├── loginForm.tsx │ │ │ └── loginPage.tsx │ ├── index.html │ ├── index.tsx │ └── tsConfig.json └── webpack.config.js ├── package.json └── src ├── index.dev.js ├── public ├── babel.config.js ├── dist │ └── local │ │ ├── Menlo-Regular.ttf │ │ ├── favicon.ico │ │ └── index.html ├── js │ ├── App.js │ ├── App.less │ ├── components │ │ ├── explorerBar │ │ │ ├── ExplorerBarContainer.js │ │ │ └── component │ │ │ │ ├── ExplorerBar.js │ │ │ │ └── ExplorerBar.less │ │ ├── footer │ │ │ └── index.js │ │ ├── sideBar │ │ │ ├── SideBarContainer.js │ │ │ └── component │ │ │ │ ├── Code │ │ │ │ ├── index.js │ │ │ │ └── index.less │ │ │ │ ├── CrumbsTab │ │ │ │ ├── index.js │ │ │ │ └── index.less │ │ │ │ ├── DependenciesTab │ │ │ │ ├── index.js │ │ │ │ └── index.less │ │ │ │ ├── FlowChartTab │ │ │ │ ├── index.js │ │ │ │ └── index.less │ │ │ │ ├── SideBar.js │ │ │ │ ├── SideBar.less │ │ │ │ └── shared │ │ │ │ └── utils.js │ │ ├── topBar │ │ │ ├── controls │ │ │ │ ├── Copy │ │ │ │ │ └── index.js │ │ │ │ ├── FlowSelect │ │ │ │ │ ├── index.js │ │ │ │ │ └── index.less │ │ │ │ ├── SettingsControl │ │ │ │ │ ├── index.js │ │ │ │ │ └── index.less │ │ │ │ ├── ViewSwitches │ │ │ │ │ ├── Item │ │ │ │ │ │ ├── ViewSwitch.js │ │ │ │ │ │ └── ViewSwitch.less │ │ │ │ │ ├── List │ │ │ │ │ │ ├── ViewSwitchList.js │ │ │ │ │ │ └── ViewSwitchList.less │ │ │ │ │ └── ViewSwitchesContainer.js │ │ │ │ └── ZoomControl │ │ │ │ │ ├── index.js │ │ │ │ │ └── index.less │ │ │ └── subPanel │ │ │ │ ├── SubPanelContainer.js │ │ │ │ └── SubPanelContainer.less │ │ └── treeDiagram │ │ │ ├── TreeDiagamsContainer.less │ │ │ ├── TreeDiagramsContainer.js │ │ │ └── component │ │ │ ├── Edge │ │ │ ├── CodeCrumbEdge.js │ │ │ ├── DepenenciesEdge.js │ │ │ ├── SourceEdge.js │ │ │ └── index.less │ │ │ ├── Icons │ │ │ ├── Arrow.js │ │ │ ├── DepCircles.js │ │ │ ├── Dot.js │ │ │ ├── Folder.js │ │ │ ├── index.less │ │ │ └── language │ │ │ │ ├── CppFile.js │ │ │ │ ├── File.js │ │ │ │ ├── JavaScriptFile.js │ │ │ │ └── PythonFile.js │ │ │ ├── Node │ │ │ ├── CodeCrumb.js │ │ │ ├── File.js │ │ │ ├── Folder.js │ │ │ └── index.less │ │ │ ├── StandalonePlaceholder │ │ │ ├── index.js │ │ │ └── index.less │ │ │ ├── Tree │ │ │ ├── CodeCrumbs │ │ │ │ ├── ExtraInfo │ │ │ │ │ ├── index.js │ │ │ │ │ └── index.less │ │ │ │ ├── FlowEdge.js │ │ │ │ ├── Tree.js │ │ │ │ ├── helpers.js │ │ │ │ └── index.js │ │ │ ├── Dependencies │ │ │ │ ├── index.js │ │ │ │ └── utils.js │ │ │ └── Source │ │ │ │ ├── Tree.js │ │ │ │ └── index.js │ │ │ ├── TreeDiagram.js │ │ │ ├── TreeDiagram.less │ │ │ ├── UnderLayer │ │ │ ├── index.js │ │ │ └── index.less │ │ │ ├── animcations.less │ │ │ └── constants.js │ ├── core │ │ ├── constants │ │ │ └── index.js │ │ ├── controlsBus │ │ │ ├── actions.js │ │ │ ├── constants.js │ │ │ ├── reducer.js │ │ │ └── selectors.js │ │ ├── dataBus │ │ │ ├── actions.js │ │ │ ├── connection.js │ │ │ ├── constants.js │ │ │ ├── index.js │ │ │ ├── reducer.js │ │ │ ├── selectors.js │ │ │ └── utils │ │ │ │ ├── geometry.js │ │ │ │ ├── index.js │ │ │ │ └── treeLayout.js │ │ ├── namespaceIntegration │ │ │ ├── actions.js │ │ │ ├── constants.js │ │ │ ├── reducer.js │ │ │ ├── selectors.js │ │ │ └── utils │ │ │ │ └── sharedCcFlows.js │ │ └── store │ │ │ ├── index.js │ │ │ └── sagas.js │ ├── index.js │ ├── meta.js │ ├── public-path.js │ ├── shared-constants.js │ └── utils │ │ └── index.js ├── webpack.common.js ├── webpack.dev.js └── webpack.local.js └── server ├── api └── index.js ├── code-parse ├── index.js ├── language │ ├── cpp │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── csharp │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── default │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── fortran │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── golang │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── haskell │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── index.js │ ├── java │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── javascript │ │ ├── astParse.js │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── kotlin │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── lua │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── ocaml │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── perl │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── php │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ ├── extensions.js │ │ ├── namespaces.js │ │ └── parser.js │ ├── python │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ ├── ruby │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js │ └── typescript │ │ ├── astParse.js │ │ ├── codecrumbs.js │ │ ├── dependencies.js │ │ └── extensions.js └── path.js ├── config.js ├── index.js ├── mediator.js ├── project-source ├── file-system.js ├── index.js ├── utils.js └── watcher.js ├── shared-constants.js ├── source-watcher.js └── utils ├── file.js ├── jsDependencies.js ├── logger.js ├── traversal.js └── tree.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Build directories 5 | src/public/dist/local/bundle/ 6 | build/ 7 | 8 | # example for dev 9 | # example-project 10 | 11 | # Remove some common IDE working directories 12 | .idea 13 | .DS_STORE 14 | 15 | yarn.lock 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | example-project 3 | docs 4 | src/public/js 5 | build 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "parser": "babylon", 4 | "singleQuote": true, 5 | "tabWidth": 2 6 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14-slim 2 | 3 | WORKDIR /usr/src/codecrumbs 4 | 5 | COPY package*.json ./ 6 | 7 | RUN yarn install 8 | 9 | COPY . . 10 | 11 | EXPOSE 2018 3018 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Bohdan Liashenko 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /cli/index.cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const path = require('path'); 4 | const program = require('commander'); 5 | const colors = require('colors'); 6 | const _ = require('lodash'); 7 | 8 | const showUpdatesInfo = require('./updatesInfo'); 9 | const server = require('../src/server'); 10 | 11 | showUpdatesInfo(); 12 | 13 | program 14 | .option('-e, --entry [entryPoint]', 'Specify path to entry point file. E.g. `src/app.js`') 15 | .option('-d, --dir [projectDir]', 'Specify path to project source code directory. E.g. `src`', '') 16 | .option( 17 | '-w, --webpack [webpackConfigFile]', 18 | 'Specify path to webpack config file. E.g. webpack.config.js' 19 | ) 20 | .option( 21 | '-t, --tsconfig [tsConfigFile]', 22 | 'Specify path to typeScript config file. E.g. tsConfig.json' 23 | ) 24 | .option('-p, --port [defaultPort]', 'Specify port for Codecrumbs client. E.g. 3333', 2018) 25 | .option('-i, --ideCmd [ideCmd]', 'IDE command to open file') 26 | .option('-x, --excludeDir [excludeDirectories]', 'Exclude directories') 27 | .option('-n, --projectName [projectNameAlias]', 'Project name alias') 28 | .option('-C, --configFile [pathToConfigFile]', 'Path to codecrumbs.config.js') 29 | .option('-D, --debugModeEnabled [debugModeEnabled]', 'Enable debug mode for logs.') 30 | .parse(process.argv); 31 | 32 | const pathToConfigFile = program.configFile || 'codecrumbs.config.js'; 33 | const configFileExists = server.checkIfPathExists(pathToConfigFile); 34 | if ((!program.entry || !program.dir) && !configFileExists) { 35 | console.log( 36 | colors.magenta( 37 | 'Please specify `entryPoint` and `projectDir` params (e.g. `codecrumbs -e src/app.js -d src`). Or use `-C codecrumbs.config.js` instead.' 38 | ) 39 | ); 40 | process.exit(); 41 | } 42 | 43 | const configFromFile = configFileExists ? require(path.resolve(pathToConfigFile)) : {}; 44 | 45 | const configFromCLI = { 46 | projectNameAlias: program.projectName, 47 | entryPoint: program.entry, 48 | projectDir: program.dir, 49 | webpackConfigPath: program.webpack, 50 | tsConfigPath: program.tsconfig, 51 | clientPort: program.port, 52 | excludeDir: program.excludeDir, 53 | ideCmd: program.ideCmd, 54 | debugModeEnabled: program.debugModeEnabled 55 | }; 56 | 57 | server.setup(_.merge(configFromCLI, configFromFile), { isDev: false }); 58 | -------------------------------------------------------------------------------- /cli/updatesInfo.js: -------------------------------------------------------------------------------- 1 | const colors = require('colors'); 2 | const exec = require('child_process').exec; 3 | 4 | module.exports = () => { 5 | try { 6 | exec('npm outdated codecrumbs').stdout.on('data', function(data) { 7 | const list = data 8 | .split(' ') 9 | .filter(v => !!v) 10 | .map(v => v.trim()); 11 | 12 | const latestVersion = list[list.length - 2]; 13 | console.log( 14 | colors.cyan.underline( 15 | `There is new version of codecrumbs (${latestVersion}) available! Please update to have all latest features and improvements!` 16 | ) 17 | ); 18 | }); 19 | } catch (e) {} 20 | }; 21 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | }; 4 | -------------------------------------------------------------------------------- /docs/cc-ui-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/cc-ui-3.png -------------------------------------------------------------------------------- /docs/dep-ui-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/dep-ui-2.png -------------------------------------------------------------------------------- /docs/dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/dev.png -------------------------------------------------------------------------------- /docs/flow-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/flow-ui.png -------------------------------------------------------------------------------- /docs/ide-integration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/ide-integration.gif -------------------------------------------------------------------------------- /docs/live-changes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/live-changes.gif -------------------------------------------------------------------------------- /docs/logo-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/logo-sm.png -------------------------------------------------------------------------------- /docs/main-ui-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/main-ui-3.png -------------------------------------------------------------------------------- /docs/multi-codebase-cc-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/docs/multi-codebase-cc-2.png -------------------------------------------------------------------------------- /example-project/codecrumbs.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entryPoint: 'example-project/src-client/index.js', 3 | projectDir: 'example-project/src-client', 4 | clientPort: 1234, 5 | projectNameAlias: 'example-project-for-client', 6 | debugModeEnabled: true 7 | }; 8 | -------------------------------------------------------------------------------- /example-project/debug/index.js: -------------------------------------------------------------------------------- 1 | //cc:debug#0;step 0 -------------------------------------------------------------------------------- /example-project/debug/sections/one.js: -------------------------------------------------------------------------------- 1 | //cc:debug#2;step 2 -------------------------------------------------------------------------------- /example-project/debug/sections/two.js: -------------------------------------------------------------------------------- 1 | //cc:debug#4;step 4 2 | 3 | //cc:debug#1;step 1 -------------------------------------------------------------------------------- /example-project/debug/utils/changeListener/behaviour.js: -------------------------------------------------------------------------------- 1 | //cc:debug#3;step 3 2 | -------------------------------------------------------------------------------- /example-project/debug/x1/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/example-project/debug/x1/index.js -------------------------------------------------------------------------------- /example-project/debug/x2/ok/ok.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/example-project/debug/x2/ok/ok.js -------------------------------------------------------------------------------- /example-project/debug/x2/x/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/example-project/debug/x2/x/index.js -------------------------------------------------------------------------------- /example-project/languages/cpp-lang.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //cc:main function 5 | int main() 6 | { 7 | cout << "Hello, World!"; 8 | return 0; 9 | } -------------------------------------------------------------------------------- /example-project/languages/csharp-lang.cs: -------------------------------------------------------------------------------- 1 | //cc:main function 2 | using System; 3 | namespace HelloWorld 4 | { 5 | class Hello 6 | { 7 | static void Main() 8 | { 9 | Console.WriteLine("Hello World!"); 10 | 11 | // Keep the console window open in debug mode. 12 | Console.WriteLine("Press any key to exit."); 13 | Console.ReadKey(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /example-project/languages/fortran-lang.f: -------------------------------------------------------------------------------- 1 | ! cc: main function 2 | program hello 3 | print *, "Hello World!" 4 | end program hello -------------------------------------------------------------------------------- /example-project/languages/go-lang.go: -------------------------------------------------------------------------------- 1 | package main 2 | import "fmt" 3 | 4 | // cc:main function 5 | func main() { 6 | fmt.Println("hello world") 7 | } 8 | -------------------------------------------------------------------------------- /example-project/languages/haskell-lang.hs: -------------------------------------------------------------------------------- 1 | -- cc:main function 2 | putStrLn "Hello, world!" 3 | -------------------------------------------------------------------------------- /example-project/languages/java-lang.java: -------------------------------------------------------------------------------- 1 | public class HelloWorld { 2 | 3 | //cc: main function 4 | public static void main(String[] args) { 5 | // Prints "Hello, World" to the terminal window. 6 | System.out.println("Hello, World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /example-project/languages/js-lang.js: -------------------------------------------------------------------------------- 1 | //cc:main function 2 | function greeting() { 3 | console.log('Hello world!'); 4 | } -------------------------------------------------------------------------------- /example-project/languages/kotlin-lang.kt: -------------------------------------------------------------------------------- 1 | //cc:main function 2 | 3 | fun main(args : Array) { 4 | println("Hello, World!") 5 | } -------------------------------------------------------------------------------- /example-project/languages/lua-lang.lua: -------------------------------------------------------------------------------- 1 | -- hello world program 2 | print ("Hello World!") 3 | -------------------------------------------------------------------------------- /example-project/languages/ocaml.ml: -------------------------------------------------------------------------------- 1 | /* cc:main function */ 2 | let hello = () => "Hello, World!"; 3 | -------------------------------------------------------------------------------- /example-project/languages/perl-lang.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | # cc: main function. 7 | print "Hello, World!\n"; 8 | -------------------------------------------------------------------------------- /example-project/languages/php-lang.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example-project/languages/python-lang.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # cc:main function 4 | def main(argv=None): 5 | if argv is None: 6 | argv = sys.argv 7 | 8 | print "Hello, world" 9 | 10 | return -------------------------------------------------------------------------------- /example-project/languages/ruby-lang.rb: -------------------------------------------------------------------------------- 1 | # cc:main function 2 | 3 | puts 'Hello, world!' 4 | -------------------------------------------------------------------------------- /example-project/languages/ts-lang.ts: -------------------------------------------------------------------------------- 1 | //cc:main function 2 | function greeting() { 3 | console.log('Hello world!'); 4 | } -------------------------------------------------------------------------------- /example-project/src-client/auth/action-types.js: -------------------------------------------------------------------------------- 1 | export const INIT_AUTH = 'INIT_AUTH'; 2 | 3 | export const SIGN_IN_ERROR = 'SIGN_IN_ERROR'; 4 | export const SIGN_IN_SUCCESS = 'SIGN_IN_SUCCESS'; 5 | 6 | export const SIGN_OUT_SUCCESS = 'SIGN_OUT_SUCCESS'; 7 | -------------------------------------------------------------------------------- /example-project/src-client/auth/actions.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase'; 2 | import { firebaseAuth } from '../firebase'; 3 | import { 4 | INIT_AUTH, 5 | SIGN_IN_ERROR, 6 | SIGN_IN_SUCCESS, 7 | SIGN_OUT_SUCCESS 8 | } from './action-types'; 9 | 10 | 11 | function authenticate(provider) { 12 | return dispatch => { 13 | //cc:signin#1;firebase sign in;+1;call to firebase with auth provider, proceed if success response 14 | firebaseAuth.signInWithPopup(provider) 15 | .then(result => dispatch(signInSuccess(result))) 16 | .catch(error => dispatch(signInError(error))); 17 | }; 18 | } 19 | 20 | 21 | export function initAuth(user) { 22 | return { 23 | type: INIT_AUTH, 24 | payload: user 25 | }; 26 | } 27 | 28 | 29 | export function signInError(error) { 30 | return { 31 | type: SIGN_IN_ERROR, 32 | payload: error 33 | }; 34 | } 35 | 36 | 37 | export function signInSuccess(result) { 38 | return { 39 | type: SIGN_IN_SUCCESS, 40 | payload: result.user 41 | }; 42 | } 43 | 44 | 45 | export function signInWithGithub() { 46 | return authenticate(new firebase.auth.GithubAuthProvider()); 47 | } 48 | 49 | 50 | export function signInWithGoogle() { 51 | return authenticate(new firebase.auth.GoogleAuthProvider()); 52 | } 53 | 54 | 55 | export function signInWithTwitter() { 56 | return authenticate(new firebase.auth.TwitterAuthProvider()); 57 | } 58 | 59 | 60 | export function signOut() { 61 | return dispatch => { 62 | firebaseAuth.signOut() 63 | .then(() => dispatch(signOutSuccess())); 64 | }; 65 | } 66 | 67 | 68 | export function signOutSuccess() { 69 | return { 70 | type: SIGN_OUT_SUCCESS 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /example-project/src-client/auth/auth.js: -------------------------------------------------------------------------------- 1 | import { firebaseAuth } from '../firebase'; 2 | import * as authActions from './actions'; 3 | 4 | 5 | export function initAuth(dispatch) { 6 | return new Promise((resolve, reject) => { 7 | const unsubscribe = firebaseAuth.onAuthStateChanged( 8 | authUser => { 9 | dispatch(authActions.initAuth(authUser)); 10 | unsubscribe(); 11 | resolve(); 12 | }, 13 | error => reject(error) 14 | ); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /example-project/src-client/auth/index.js: -------------------------------------------------------------------------------- 1 | import * as authActions from './actions'; 2 | 3 | 4 | export { authActions }; 5 | export * from './action-types'; 6 | export { initAuth } from './auth'; 7 | export { authReducer } from './reducer'; 8 | export { getAuth, isAuthenticated } from './selectors'; 9 | -------------------------------------------------------------------------------- /example-project/src-client/auth/reducer.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable'; 2 | import { INIT_AUTH, SIGN_IN_SUCCESS, SIGN_OUT_SUCCESS } from './action-types'; 3 | 4 | 5 | export const AuthState = new Record({ 6 | authenticated: false, 7 | id: null 8 | }); 9 | 10 | 11 | export function authReducer(state = new AuthState(), {payload, type}) { 12 | switch (type) { 13 | case INIT_AUTH: 14 | case SIGN_IN_SUCCESS: 15 | return state.merge({ 16 | authenticated: !!payload, //cc:signin#5;toggle 'authenticated' flag 17 | id: payload ? payload.uid : null 18 | }); 19 | 20 | case SIGN_OUT_SUCCESS: 21 | return new AuthState(); 22 | 23 | default: 24 | return state; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example-project/src-client/auth/selectors.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | 3 | 4 | export function isAuthenticated(state) { 5 | return getAuth(state).authenticated; 6 | } 7 | 8 | 9 | //===================================== 10 | // MEMOIZED SELECTORS 11 | //------------------------------------- 12 | 13 | export const getAuth = createSelector( 14 | state => state.auth, 15 | auth => auth.toJS() 16 | ); 17 | -------------------------------------------------------------------------------- /example-project/src-client/firebase/config.js: -------------------------------------------------------------------------------- 1 | //cc:firebase config;and some details 2 | export const firebaseConfig = { 3 | apiKey: 'AIzaSyBsVVpEDrlNPEmshLcmOuE0FxhjPn0AqMg', 4 | authDomain: 'todo-react-redux.firebaseapp.com', 5 | databaseURL: 'https://todo-react-redux.firebaseio.com', 6 | storageBucket: 'firebase-todo-react-redux.appspot.com' 7 | }; 8 | -------------------------------------------------------------------------------- /example-project/src-client/firebase/firebase-list.js: -------------------------------------------------------------------------------- 1 | import { firebaseDb } from './firebase'; 2 | 3 | 4 | export class FirebaseList { 5 | constructor(actions, modelClass, path = null) { 6 | this._actions = actions; 7 | this._modelClass = modelClass; 8 | this._path = path; 9 | } 10 | 11 | get path() { 12 | return this._path; 13 | } 14 | 15 | set path(value) { 16 | this._path = value; 17 | } 18 | 19 | push(value) { 20 | return new Promise((resolve, reject) => { 21 | firebaseDb.ref(this._path) 22 | .push(value, error => error ? reject(error) : resolve()); 23 | }); 24 | } 25 | 26 | remove(key) { 27 | return new Promise((resolve, reject) => { 28 | firebaseDb.ref(`${this._path}/${key}`) 29 | .remove(error => error ? reject(error) : resolve()); 30 | }); 31 | } 32 | 33 | set(key, value) { 34 | return new Promise((resolve, reject) => { 35 | firebaseDb.ref(`${this._path}/${key}`) 36 | .set(value, error => error ? reject(error) : resolve()); 37 | }); 38 | } 39 | 40 | update(key, value) { 41 | return new Promise((resolve, reject) => { 42 | firebaseDb.ref(`${this._path}/${key}`) 43 | .update(value, error => error ? reject(error) : resolve()); 44 | }); 45 | } 46 | 47 | subscribe(emit) { 48 | let ref = firebaseDb.ref(this._path); 49 | let initialized = false; 50 | let list = []; 51 | 52 | ref.once('value', () => { 53 | initialized = true; 54 | emit(this._actions.onLoad(list)); 55 | }); 56 | 57 | ref.on('child_added', snapshot => { 58 | if (initialized) { 59 | emit(this._actions.onAdd(this.unwrapSnapshot(snapshot))); 60 | } 61 | else { 62 | list.push(this.unwrapSnapshot(snapshot)); 63 | } 64 | }); 65 | 66 | ref.on('child_changed', snapshot => { 67 | emit(this._actions.onChange(this.unwrapSnapshot(snapshot))); 68 | }); 69 | 70 | ref.on('child_removed', snapshot => { 71 | emit(this._actions.onRemove(this.unwrapSnapshot(snapshot))); 72 | }); 73 | 74 | this._unsubscribe = () => ref.off(); 75 | } 76 | 77 | unsubscribe() { 78 | this._unsubscribe(); 79 | } 80 | 81 | unwrapSnapshot(snapshot) { 82 | let attrs = snapshot.val(); 83 | attrs.key = snapshot.key; 84 | return new this._modelClass(attrs); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /example-project/src-client/firebase/firebase.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/app'; 2 | 3 | import 'firebase/auth'; 4 | import 'firebase/database'; 5 | 6 | import { firebaseConfig } from './config'; 7 | 8 | export const firebaseApp = firebase.initializeApp(firebaseConfig); 9 | export const firebaseAuth = firebase.auth(); 10 | export const firebaseDb = firebase.database(); 11 | -------------------------------------------------------------------------------- /example-project/src-client/firebase/index.js: -------------------------------------------------------------------------------- 1 | export { firebaseApp, firebaseAuth, firebaseDb } from './firebase'; 2 | export { FirebaseList } from './firebase-list'; 3 | -------------------------------------------------------------------------------- /example-project/src-client/history.js: -------------------------------------------------------------------------------- 1 | import createHistory from 'history/createBrowserHistory'; 2 | 3 | 4 | export default createHistory(); -------------------------------------------------------------------------------- /example-project/src-client/index.js: -------------------------------------------------------------------------------- 1 | import './views/styles/styles.css'; 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import { Provider } from 'react-redux'; 6 | import { ConnectedRouter } from 'react-router-redux'; 7 | 8 | import { initAuth } from './auth'; 9 | import history from './history'; 10 | import configureStore from './store'; 11 | import registerServiceWorker from './utils/register-service-worker'; 12 | import App from './views/app'; 13 | 14 | 15 | const store = configureStore(); 16 | const rootElement = document.getElementById('root'); 17 | 18 | //cc:layout#0;start 19 | function render(Component) { 20 | ReactDOM.render( 21 | 22 | 23 |
24 | 25 |
26 |
27 |
, 28 | rootElement 29 | ); 30 | } 31 | 32 | 33 | if (module.hot) { 34 | module.hot.accept('./views/app', () => { 35 | render(require('./views/app').default); 36 | }) 37 | } 38 | 39 | 40 | registerServiceWorker(); 41 | 42 | initAuth(store.dispatch) 43 | .then(() => render(App)) 44 | .catch(error => console.error(error)); 45 | -------------------------------------------------------------------------------- /example-project/src-client/notification/action-types.js: -------------------------------------------------------------------------------- 1 | export const DISMISS_NOTIFICATION = 'DISMISS_NOTIFICATION'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/notification/actions.js: -------------------------------------------------------------------------------- 1 | import { DISMISS_NOTIFICATION } from './action-types'; 2 | 3 | 4 | export function dismissNotification() { 5 | return { 6 | type: DISMISS_NOTIFICATION 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /example-project/src-client/notification/index.js: -------------------------------------------------------------------------------- 1 | import * as notificationActions from './actions'; 2 | 3 | 4 | export { notificationActions }; 5 | export * from './action-types'; 6 | export { notificationReducer } from './reducer'; 7 | export { getNotification } from './selectors'; 8 | -------------------------------------------------------------------------------- /example-project/src-client/notification/reducer.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable'; 2 | import { REMOVE_TASK_SUCCESS } from '../tasks'; 3 | import { DISMISS_NOTIFICATION } from './action-types'; 4 | 5 | 6 | export const NotificationState = new Record({ 7 | actionLabel: '', 8 | display: false, 9 | message: '' 10 | }); 11 | 12 | 13 | export function notificationReducer(state = new NotificationState(), action) { 14 | switch (action.type) { 15 | case REMOVE_TASK_SUCCESS: 16 | return state.merge({ 17 | actionLabel: 'Undo', 18 | display: true, 19 | message: 'Task deleted' 20 | }); 21 | 22 | case DISMISS_NOTIFICATION: 23 | return new NotificationState(); 24 | 25 | default: 26 | return new NotificationState(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example-project/src-client/notification/selectors.js: -------------------------------------------------------------------------------- 1 | export function getNotification(state) { 2 | return state.notification; 3 | } 4 | -------------------------------------------------------------------------------- /example-project/src-client/reducers.js: -------------------------------------------------------------------------------- 1 | import { routerReducer } from 'react-router-redux'; 2 | import { combineReducers } from 'redux'; 3 | import { authReducer } from './auth'; 4 | import { notificationReducer } from './notification'; 5 | import { tasksReducer } from './tasks'; 6 | 7 | 8 | export default combineReducers({ 9 | auth: authReducer, 10 | notification: notificationReducer, 11 | routing: routerReducer, 12 | tasks: tasksReducer 13 | }); 14 | -------------------------------------------------------------------------------- /example-project/src-client/store.js: -------------------------------------------------------------------------------- 1 | import { routerMiddleware } from 'react-router-redux'; 2 | import { applyMiddleware, compose, createStore } from 'redux'; 3 | import thunk from 'redux-thunk'; 4 | import history from './history'; 5 | import reducers from './reducers'; 6 | 7 | 8 | export default (initialState = {}) => { 9 | let middleware = applyMiddleware(thunk, routerMiddleware(history)); 10 | 11 | if (process.env.NODE_ENV !== 'production') { 12 | const devToolsExtension = window.devToolsExtension; 13 | if (typeof devToolsExtension === 'function') { 14 | middleware = compose(middleware, devToolsExtension()); 15 | } 16 | } 17 | 18 | const store = createStore(reducers, initialState, middleware); 19 | 20 | if (module.hot) { 21 | module.hot.accept('./reducers', () => { 22 | store.replaceReducer(require('./reducers').default); 23 | }); 24 | } 25 | 26 | return store; 27 | }; 28 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/action-types.js: -------------------------------------------------------------------------------- 1 | export const CREATE_TASK_ERROR = 'CREATE_TASK_ERROR'; 2 | export const CREATE_TASK_SUCCESS = 'CREATE_TASK_SUCCESS'; 3 | 4 | export const REMOVE_TASK_ERROR = 'REMOVE_TASK_ERROR'; 5 | export const REMOVE_TASK_SUCCESS = 'REMOVE_TASK_SUCCESS'; 6 | 7 | export const UNDELETE_TASK_ERROR = 'UNDELETE_TASK_ERROR'; 8 | 9 | export const UPDATE_TASK_ERROR = 'UPDATE_TASK_ERROR'; 10 | export const UPDATE_TASK_SUCCESS = 'UPDATE_TASK_SUCCESS'; 11 | 12 | export const FILTER_TASKS = 'FILTER_TASKS'; 13 | export const LOAD_TASKS_SUCCESS = 'LOAD_TASKS_SUCCESS'; 14 | export const UNLOAD_TASKS_SUCCESS = 'UNLOAD_TASKS_SUCCESS'; 15 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/actions.js: -------------------------------------------------------------------------------- 1 | import { getDeletedTask } from './selectors'; 2 | import { taskList } from './task-list'; 3 | import { 4 | CREATE_TASK_ERROR, 5 | CREATE_TASK_SUCCESS, 6 | REMOVE_TASK_ERROR, 7 | REMOVE_TASK_SUCCESS, 8 | FILTER_TASKS, 9 | LOAD_TASKS_SUCCESS, 10 | UNDELETE_TASK_ERROR, 11 | UNLOAD_TASKS_SUCCESS, 12 | UPDATE_TASK_ERROR, 13 | UPDATE_TASK_SUCCESS 14 | } from './action-types'; 15 | 16 | 17 | export function createTask(title) { 18 | return dispatch => { 19 | taskList.push({completed: false, title}) 20 | .catch(error => dispatch(createTaskError(error))); 21 | }; 22 | } 23 | 24 | export function createTaskError(error) { 25 | return { 26 | type: CREATE_TASK_ERROR, 27 | payload: error 28 | }; 29 | } 30 | 31 | export function createTaskSuccess(task) { 32 | return { 33 | type: CREATE_TASK_SUCCESS, 34 | payload: task 35 | }; 36 | } 37 | 38 | export function removeTask(task) { 39 | return dispatch => { 40 | taskList.remove(task.key) 41 | .catch(error => dispatch(removeTaskError(error))); 42 | }; 43 | } 44 | 45 | export function removeTaskError(error) { 46 | return { 47 | type: REMOVE_TASK_ERROR, 48 | payload: error 49 | }; 50 | } 51 | 52 | export function removeTaskSuccess(task) { 53 | return { 54 | type: REMOVE_TASK_SUCCESS, 55 | payload: task 56 | }; 57 | } 58 | 59 | export function undeleteTask() { 60 | return (dispatch, getState) => { 61 | const task = getDeletedTask(getState()); 62 | if (task) { 63 | taskList.set(task.key, {completed: task.completed, title: task.title}) 64 | .catch(error => dispatch(undeleteTaskError(error))); 65 | } 66 | }; 67 | } 68 | 69 | export function undeleteTaskError(error) { 70 | return { 71 | type: UNDELETE_TASK_ERROR, 72 | payload: error 73 | }; 74 | } 75 | 76 | export function updateTaskError(error) { 77 | return { 78 | type: UPDATE_TASK_ERROR, 79 | payload: error 80 | }; 81 | } 82 | 83 | export function updateTask(task, changes) { 84 | return dispatch => { 85 | taskList.update(task.key, changes) 86 | .catch(error => dispatch(updateTaskError(error))); 87 | }; 88 | } 89 | 90 | export function updateTaskSuccess(task) { 91 | return { 92 | type: UPDATE_TASK_SUCCESS, 93 | payload: task 94 | }; 95 | } 96 | 97 | export function loadTasksSuccess(tasks) { 98 | return { 99 | type: LOAD_TASKS_SUCCESS, 100 | payload: tasks 101 | }; 102 | } 103 | 104 | export function filterTasks(filterType) { 105 | return { 106 | type: FILTER_TASKS, 107 | payload: {filterType} 108 | }; 109 | } 110 | 111 | export function loadTasks() { 112 | return (dispatch, getState) => { 113 | const { auth } = getState(); 114 | taskList.path = `tasks/${auth.id}`; 115 | taskList.subscribe(dispatch); 116 | }; 117 | } 118 | 119 | export function unloadTasks() { 120 | taskList.unsubscribe(); 121 | return { 122 | type: UNLOAD_TASKS_SUCCESS 123 | }; 124 | } 125 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/index.js: -------------------------------------------------------------------------------- 1 | import * as tasksActions from './actions'; 2 | 3 | 4 | export { tasksActions }; 5 | export * from './action-types'; 6 | export { tasksReducer } from './reducer'; 7 | export { getTaskFilter, getVisibleTasks } from './selectors'; 8 | export { Task } from './task'; 9 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/reducer.js: -------------------------------------------------------------------------------- 1 | import { List, Record } from 'immutable'; 2 | import { SIGN_OUT_SUCCESS } from '../auth/action-types'; 3 | import { 4 | CREATE_TASK_SUCCESS, 5 | REMOVE_TASK_SUCCESS, 6 | FILTER_TASKS, 7 | LOAD_TASKS_SUCCESS, 8 | UPDATE_TASK_SUCCESS 9 | } from './action-types'; 10 | 11 | 12 | export const TasksState = new Record({ 13 | deleted: null, 14 | filter: '', 15 | list: new List(), 16 | previous: null 17 | }); 18 | 19 | 20 | export function tasksReducer(state = new TasksState(), {payload, type}) { 21 | switch (type) { 22 | case CREATE_TASK_SUCCESS: 23 | return state.merge({ 24 | deleted: null, 25 | previous: null, 26 | list: state.deleted && state.deleted.key === payload.key ? 27 | state.previous : 28 | state.list.unshift(payload) 29 | }); 30 | 31 | case REMOVE_TASK_SUCCESS: 32 | return state.merge({ 33 | deleted: payload, 34 | previous: state.list, 35 | list: state.list.filter(task => task.key !== payload.key) 36 | }); 37 | 38 | case FILTER_TASKS: 39 | return state.set('filter', payload.filterType || ''); 40 | 41 | case LOAD_TASKS_SUCCESS: 42 | return state.set('list', new List(payload.reverse())); 43 | 44 | case UPDATE_TASK_SUCCESS: 45 | return state.merge({ 46 | deleted: null, 47 | previous: null, 48 | list: state.list.map(task => { 49 | return task.key === payload.key ? payload : task; 50 | }) 51 | }); 52 | 53 | case SIGN_OUT_SUCCESS: 54 | return new TasksState(); 55 | 56 | default: 57 | return state; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/selectors.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | 3 | 4 | export function getTasks(state) { 5 | return state.tasks; 6 | } 7 | 8 | export function getTaskList(state) { 9 | return getTasks(state).list; 10 | } 11 | 12 | export function getTaskFilter(state) { 13 | return getTasks(state).filter; 14 | } 15 | 16 | export function getDeletedTask(state) { 17 | return getTasks(state).deleted; 18 | } 19 | 20 | 21 | //===================================== 22 | // MEMOIZED SELECTORS 23 | //------------------------------------- 24 | 25 | export const getVisibleTasks = createSelector( 26 | getTaskList, 27 | getTaskFilter, 28 | (tasks, filter) => { 29 | switch (filter) { 30 | case 'active': 31 | return tasks.filter(task => !task.completed); 32 | 33 | case 'completed': 34 | return tasks.filter(task => task.completed); 35 | 36 | default: 37 | return tasks; 38 | } 39 | } 40 | ); 41 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/task-list.js: -------------------------------------------------------------------------------- 1 | import { FirebaseList } from '../firebase'; 2 | import * as taskActions from './actions'; 3 | import { Task } from './task'; 4 | 5 | 6 | export const taskList = new FirebaseList({ 7 | onAdd: taskActions.createTaskSuccess, 8 | onChange: taskActions.updateTaskSuccess, 9 | onLoad: taskActions.loadTasksSuccess, 10 | onRemove: taskActions.removeTaskSuccess 11 | }, Task); 12 | -------------------------------------------------------------------------------- /example-project/src-client/tasks/task.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable'; 2 | 3 | 4 | export const Task = new Record({ 5 | completed: false, 6 | key: null, 7 | title: null 8 | }); 9 | -------------------------------------------------------------------------------- /example-project/src-client/test_tml.vue: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | //cc:test vue 17 | -------------------------------------------------------------------------------- /example-project/src-client/utils/create-test-component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { findRenderedComponentWithType, renderIntoDocument } from 'react-dom/test-utils'; 3 | 4 | 5 | export function createTestComponent(TestComponent, props) { 6 | return findRenderedComponentWithType( 7 | renderIntoDocument(), 8 | TestComponent 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /example-project/src-client/views/app/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { withRouter } from 'react-router-dom'; 5 | 6 | import { authActions, getAuth } from '../../auth'; 7 | import Header from '../components/header'; 8 | import RequireAuthRoute from '../components/require-auth-route'; 9 | import RequireUnauthRoute from '../components/require-unauth-route'; 10 | import SignInPage from '../pages/sign-in'; 11 | import TasksPage from '../pages/tasks'; 12 | 13 | //cc:layout#1;describe pages;some details long description for separare popup 14 | const App = ({authenticated, signOut}) => ( 15 |
16 |
20 | 21 |
22 | 23 | 24 |
25 |
26 | ); 27 | 28 | App.propTypes = { 29 | authenticated: PropTypes.bool.isRequired, 30 | signOut: PropTypes.func.isRequired 31 | }; 32 | 33 | 34 | //===================================== 35 | // CONNECT 36 | //------------------------------------- 37 | 38 | const mapStateToProps = getAuth; 39 | 40 | const mapDispatchToProps = { 41 | signOut: authActions.signOut 42 | }; 43 | 44 | //cc:here 45 | export default withRouter( 46 | connect( 47 | mapStateToProps, 48 | mapDispatchToProps 49 | )(App) 50 | ); 51 | -------------------------------------------------------------------------------- /example-project/src-client/views/app/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './app'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/button/button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import PropTypes from 'prop-types'; 4 | 5 | import './button.css'; 6 | 7 | 8 | const Button = ({children, className, onClick, type = 'button'}) => { 9 | const cssClasses = classNames('btn', className); 10 | return ( 11 | 14 | ); 15 | }; 16 | 17 | Button.propTypes = { 18 | children: PropTypes.node, 19 | className: PropTypes.string, 20 | onClick: PropTypes.func, 21 | type: PropTypes.oneOf(['button', 'reset', 'submit']) 22 | }; 23 | 24 | 25 | export default Button; 26 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/button/button.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .btn { 5 | @include button-base; 6 | outline: none; 7 | border: 0; 8 | padding: 0; 9 | overflow: hidden; 10 | transform: translate(0, 0); 11 | background: transparent; 12 | } 13 | 14 | .btn--icon { 15 | border-radius: 40px; 16 | padding: 8px; 17 | width: 40px; 18 | height: 40px; 19 | } 20 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './button'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/github-logo/github-logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | 4 | export default function GitHubLogo() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/github-logo/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './github-logo'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/header/header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Button from '../button'; 4 | import GitHubLogo from '../github-logo'; 5 | 6 | import './header.css'; 7 | 8 | const Header = ({authenticated, signOut}) => ( 9 |
10 |
11 |
12 |

Todo React Redux

13 | 14 |
    15 | {authenticated ?
  • : null} 16 |
  • 17 | 18 | 19 | 20 |
  • 21 |
22 |
23 |
24 |
25 | ); 26 | 27 | Header.propTypes = { 28 | authenticated: PropTypes.bool.isRequired, 29 | signOut: PropTypes.func.isRequired 30 | }; 31 | 32 | 33 | export default Header; 34 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/header/header.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .header { 5 | padding: 10px 0; 6 | height: 60px; 7 | overflow: hidden; 8 | line-height: 40px; 9 | } 10 | 11 | .header__title { 12 | display: flex; 13 | align-items: center; 14 | 15 | float: left; 16 | font-size: rem(14px); 17 | font-weight: 400; 18 | line-height: 40px; 19 | text-rendering: auto; 20 | transform: translate(0,0); 21 | 22 | &:before { 23 | display: inline-block; 24 | border: 2px solid #eee; 25 | margin-right: 8px; 26 | border-radius: 100%; 27 | height: 16px; 28 | width: 16px; 29 | content: ' '; 30 | } 31 | } 32 | 33 | .header__actions { 34 | @include clearfix; 35 | float: right; 36 | padding: 8px 0; 37 | line-height: 24px; 38 | 39 | li { 40 | float: left; 41 | list-style: none; 42 | 43 | &:last-child { 44 | margin-left: 12px; 45 | padding-left: 12px; 46 | border-left: 1px solid #333; 47 | } 48 | 49 | &:first-child { 50 | border: none; 51 | } 52 | } 53 | 54 | .btn { 55 | display: block; 56 | margin: 0; 57 | color: #999; 58 | font-size: rem(14px); 59 | line-height: 24px; 60 | } 61 | 62 | .link { 63 | display: block; 64 | fill: #98999a; 65 | transform: translate(0, 0); 66 | } 67 | 68 | .link--github { 69 | padding-top: 1px; 70 | width: 22px; 71 | height: 24px; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/header/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './header'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/icon/icon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import PropTypes from 'prop-types'; 4 | 5 | 6 | const Icon = ({className, name}) => { 7 | const cssClasses = classNames('material-icons', className); 8 | return {name}; 9 | }; 10 | 11 | Icon.propTypes = { 12 | className: PropTypes.string, 13 | name: PropTypes.string.isRequired 14 | }; 15 | 16 | 17 | export default Icon; 18 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/icon/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './icon'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/notification/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './notification'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/notification/notification.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import './notification.css'; 5 | 6 | 7 | class Notification extends Component { 8 | static propTypes = { 9 | action: PropTypes.func.isRequired, 10 | actionLabel: PropTypes.string.isRequired, 11 | dismiss: PropTypes.func.isRequired, 12 | display: PropTypes.bool.isRequired, 13 | duration: PropTypes.number, 14 | message: PropTypes.string.isRequired 15 | }; 16 | 17 | componentDidMount() { 18 | this.startTimer(); 19 | } 20 | 21 | componentWillReceiveProps(nextProps) { 22 | if (nextProps.display) { 23 | this.startTimer(); 24 | } 25 | } 26 | 27 | componentWillUnmount() { 28 | this.clearTimer(); 29 | } 30 | 31 | clearTimer() { 32 | if (this.timerId) { 33 | clearTimeout(this.timerId); 34 | } 35 | } 36 | 37 | startTimer() { 38 | this.clearTimer(); 39 | this.timerId = setTimeout(() => { 40 | this.props.dismiss(); 41 | }, this.props.duration || 5000); 42 | } 43 | 44 | render() { 45 | return ( 46 |
47 |

this.message = c}>{this.props.message}

48 | 53 |
54 | ); 55 | } 56 | } 57 | 58 | export default Notification; 59 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/notification/notification.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .notification { 5 | @include clearfix; 6 | position: fixed; 7 | left: 50%; 8 | top: 60px; 9 | margin-left: -100px; 10 | border: 1px solid #aaa; 11 | padding: 10px 15px; 12 | width: 200px; 13 | font-size: rem(16px); 14 | line-height: 24px; 15 | } 16 | 17 | .notification__message { 18 | float: left; 19 | } 20 | 21 | .notification__button { 22 | float: right; 23 | font-size: rem(16px); 24 | line-height: 24px; 25 | text-transform: uppercase; 26 | color: #85bf6b; 27 | } 28 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/require-auth-route/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './require-auth-route'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/require-auth-route/require-auth-route.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Redirect } from 'react-router-dom' 3 | 4 | //cc:signin#6;enable route;details 5 | const RequireAuthRoute = ({component: Component, authenticated, ...rest}) => ( 6 | { 9 | return authenticated ? ( 10 | 11 | ) : ( 12 | 16 | ) 17 | }} 18 | /> 19 | ); 20 | 21 | 22 | export default RequireAuthRoute; 23 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/require-unauth-route/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './require-unauth-route'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/require-unauth-route/require-unauth-route.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Redirect } from 'react-router-dom' 3 | 4 | 5 | const RequireUnauthRoute = ({component: Component, authenticated, ...rest}) => ( 6 | { 9 | return authenticated ? ( 10 | 14 | ) : ( 15 | 16 | ) 17 | }} 18 | /> 19 | ); 20 | 21 | 22 | export default RequireUnauthRoute; 23 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-filters/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './task-filters'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-filters/task-filters.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { NavLink } from 'react-router-dom'; 4 | 5 | import './task-filters.css'; 6 | 7 | 8 | const TaskFilters = ({filter}) => ( 9 |
    10 |
  • !filter} to="/">View All
  • 11 |
  • filter === 'active'} to={{pathname: '/', search: '?filter=active'}}>Active
  • 12 |
  • filter === 'completed'} to={{pathname: '/', search: '?filter=completed'}}>Completed
  • 13 |
14 | ); 15 | 16 | TaskFilters.propTypes = { 17 | filter: PropTypes.string 18 | }; 19 | 20 | 21 | export default TaskFilters; 22 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-filters/task-filters.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .task-filters { 5 | @include clearfix; 6 | margin-bottom: 45px; 7 | padding-left: 1px; 8 | font-size: rem(16px); 9 | line-height: 24px; 10 | list-style-type: none; 11 | 12 | @include media-query(540) { 13 | margin-bottom: 55px; 14 | } 15 | 16 | li { 17 | float: left; 18 | 19 | &:not(:first-child) { 20 | margin-left: 12px; 21 | } 22 | 23 | &:not(:first-child):before { 24 | padding-right: 12px; 25 | content: '/'; 26 | font-weight: 300; 27 | } 28 | } 29 | 30 | a { 31 | color: #999; 32 | text-decoration: none; 33 | 34 | &.active { 35 | color: #fff; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-form/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './task-form'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-form/task-form.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import './task-form.css'; 5 | 6 | 7 | export class TaskForm extends Component { 8 | static propTypes = { 9 | handleSubmit: PropTypes.func.isRequired 10 | }; 11 | 12 | constructor() { 13 | super(...arguments); 14 | 15 | this.state = {title: ''}; 16 | 17 | this.handleChange = this.handleChange.bind(this); 18 | this.handleKeyUp = this.handleKeyUp.bind(this); 19 | this.handleSubmit = this.handleSubmit.bind(this); 20 | } 21 | 22 | clearInput() { 23 | this.setState({title: ''}); 24 | } 25 | 26 | handleChange(event) { 27 | this.setState({title: event.target.value}); 28 | } 29 | 30 | handleKeyUp(event) { 31 | if (event.keyCode === 27) this.clearInput(); 32 | } 33 | 34 | handleSubmit(event) { 35 | event.preventDefault(); 36 | const title = this.state.title.trim(); 37 | if (title.length) this.props.handleSubmit(title); 38 | this.clearInput(); 39 | } 40 | 41 | render() { 42 | return ( 43 |
44 | this.titleInput = e} 53 | type="text" 54 | value={this.state.title} 55 | /> 56 |
57 | ); 58 | } 59 | } 60 | 61 | 62 | export default TaskForm; 63 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-form/task-form.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .task-form { 5 | margin: 40px 0 10px; 6 | 7 | @include media-query(540) { 8 | margin: 80px 0 20px; 9 | } 10 | } 11 | 12 | .task-form__input { 13 | outline: none; 14 | border: 0; 15 | border-bottom: 1px dotted #666; 16 | border-radius: 0; 17 | padding: 0 0 5px 0; 18 | width: 100%; 19 | height: 50px; 20 | font-family: inherit; 21 | font-size: rem(24px); 22 | font-weight: 300; 23 | color: #fff; 24 | background: transparent; 25 | 26 | @include media-query(540) { 27 | height: 61px; 28 | font-size: rem(32px); 29 | } 30 | 31 | &::placeholder { 32 | color: #999; 33 | opacity: 1; // firefox native placeholder style has opacity < 1 34 | } 35 | 36 | &:focus::placeholder { 37 | color: #777; 38 | opacity: 1; 39 | } 40 | 41 | // webkit input doesn't inherit font-smoothing from ancestors 42 | -webkit-font-smoothing: antialiased; 43 | 44 | // remove `x` 45 | &::-ms-clear { 46 | display: none; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-item/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './task-item'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-item/task-item.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .task-item { 5 | display: flex; 6 | outline: none; 7 | border-bottom: 1px dotted #666; 8 | height: 60px; 9 | overflow: hidden; 10 | color: #fff; 11 | font-size: rem(18px); 12 | font-weight: 300; 13 | 14 | @include media-query(540) { 15 | font-size: rem(24px); 16 | } 17 | } 18 | 19 | .task-item--editing { 20 | border-bottom: 1px dotted #ccc; 21 | } 22 | 23 | 24 | //===================================== 25 | // Cells 26 | //------------------------------------- 27 | .cell { 28 | &:first-child, 29 | &:last-child { 30 | display: flex; 31 | flex: 0 0 auto; 32 | align-items: center; 33 | } 34 | 35 | &:first-child { 36 | padding-right: 20px; 37 | } 38 | 39 | &:nth-child(2) { 40 | flex: 1; 41 | padding-right: 30px; 42 | overflow: hidden; 43 | } 44 | } 45 | 46 | 47 | //===================================== 48 | // Buttons 49 | //------------------------------------- 50 | .task-item__button { 51 | margin-left: 5px; 52 | background: #2a2a2a; 53 | 54 | &:first-child { 55 | margin: 0; 56 | } 57 | 58 | color: #555; 59 | 60 | &:hover { 61 | color: #999; 62 | } 63 | 64 | &:active { 65 | background: #262626; 66 | } 67 | 68 | &.active { 69 | color: #85bf6b; 70 | } 71 | } 72 | 73 | 74 | //===================================== 75 | // Title (static) 76 | //------------------------------------- 77 | .task-item__title { 78 | display: inline-block; 79 | position: relative; 80 | max-width: 100%; 81 | line-height: 60px; 82 | outline: none; 83 | overflow: hidden; 84 | text-overflow: ellipsis; 85 | white-space: nowrap; 86 | 87 | &:after { 88 | position: absolute; 89 | left: 0; 90 | bottom: 0; 91 | border-top: 2px solid #85bf6b; 92 | width: 0; 93 | height: 46%; 94 | content: ''; 95 | } 96 | 97 | .task-item--completed & { 98 | color: #666; 99 | } 100 | 101 | .task-item--completed &:after { 102 | width: 100%; 103 | } 104 | } 105 | 106 | 107 | //===================================== 108 | // Title (input) 109 | //------------------------------------- 110 | .task-item__input { 111 | outline: none; 112 | border: 0; 113 | padding: 0; 114 | width: 100%; 115 | height: 60px; 116 | color: inherit; 117 | font: inherit; 118 | background: transparent; 119 | 120 | // hide `x` 121 | &::-ms-clear { 122 | display: none; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-list/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './task-list'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-list/task-list.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { List } from 'immutable'; 3 | import PropTypes from 'prop-types'; 4 | import TaskItem from '../task-item/task-item'; 5 | 6 | //cc:layout#3;tasks list; 7 | function TaskList({removeTask, tasks, updateTask}) { 8 | let taskItems = tasks.map((task, index) => { 9 | return ( 10 | 16 | ); 17 | }); 18 | 19 | return ( 20 |
21 | {taskItems} 22 |
23 | ); 24 | } 25 | 26 | TaskList.propTypes = { 27 | removeTask: PropTypes.func.isRequired, 28 | tasks: PropTypes.instanceOf(List).isRequired, 29 | updateTask: PropTypes.func.isRequired 30 | }; 31 | 32 | export default TaskList; 33 | -------------------------------------------------------------------------------- /example-project/src-client/views/components/task-list/task-list.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .task-list { 5 | border-top: 1px dotted #666; 6 | } 7 | -------------------------------------------------------------------------------- /example-project/src-client/views/pages/sign-in/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './sign-in-page'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/pages/sign-in/sign-in-page.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { withRouter } from 'react-router-dom'; 5 | import { authActions } from '../../../auth'; 6 | import Button from '../../../views/components/button'; 7 | 8 | import './sign-in-page.css'; 9 | 10 | 11 | const SignInPage = ({signInWithGithub, signInWithGoogle, signInWithTwitter}) => { 12 | return ( 13 |
14 |
15 |

Sign in

16 | 17 | 18 | 19 |
20 |
21 | ); 22 | }; 23 | 24 | SignInPage.propTypes = { 25 | signInWithGithub: PropTypes.func.isRequired, 26 | signInWithGoogle: PropTypes.func.isRequired, 27 | signInWithTwitter: PropTypes.func.isRequired 28 | }; 29 | 30 | 31 | //===================================== 32 | // CONNECT 33 | //------------------------------------- 34 | 35 | const mapDispatchToProps = { 36 | signInWithGithub: authActions.signInWithGithub, //cc:signin#0;dispatch action;start signin with github 37 | signInWithGoogle: authActions.signInWithGoogle, 38 | signInWithTwitter: authActions.signInWithTwitter 39 | }; 40 | //cc:signin#7;test 41 | export default withRouter( 42 | connect( 43 | null, 44 | mapDispatchToProps 45 | )(SignInPage) 46 | ); 47 | -------------------------------------------------------------------------------- /example-project/src-client/views/pages/sign-in/sign-in-page.scss: -------------------------------------------------------------------------------- 1 | @import 'views/styles/shared'; 2 | 3 | 4 | .sign-in { 5 | margin-top: 90px; 6 | max-width: 300px; 7 | } 8 | 9 | .sign-in__heading { 10 | margin-bottom: 36px; 11 | font-size: 30px; 12 | font-weight: 300; 13 | text-align: center; 14 | } 15 | 16 | .sign-in__button { 17 | margin-bottom: 10px; 18 | border: 1px solid #555; 19 | width: 100%; 20 | height: 48px; 21 | font-family: inherit; 22 | font-size: rem(18px); 23 | line-height: 48px; 24 | color: #999; 25 | 26 | &:hover { 27 | border: 2px solid #aaa; 28 | line-height: 46px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example-project/src-client/views/pages/tasks/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './tasks-page'; 2 | -------------------------------------------------------------------------------- /example-project/src-client/views/styles/_grid.scss: -------------------------------------------------------------------------------- 1 | .g-row { 2 | @include grid-row; 3 | } 4 | 5 | .g-col { 6 | @include grid-column; 7 | width: 100%; 8 | } 9 | -------------------------------------------------------------------------------- /example-project/src-client/views/styles/_settings.scss: -------------------------------------------------------------------------------- 1 | $base-background-color: #222 !default; 2 | $base-font-color: #999 !default; 3 | $base-font-family: 'aktiv-grotesk-std', Helvetica Neue, Arial, sans-serif !default; 4 | $base-font-size: 18px !default; 5 | $base-line-height: 24px !default; 6 | 7 | 8 | //===================================== 9 | // Grid 10 | //------------------------------------- 11 | $grid-max-width: 810px !default; 12 | -------------------------------------------------------------------------------- /example-project/src-client/views/styles/_shared.scss: -------------------------------------------------------------------------------- 1 | @import 2 | './settings', 3 | 'minx/src/settings', 4 | 'minx/src/functions', 5 | 'minx/src/mixins'; 6 | -------------------------------------------------------------------------------- /example-project/src-client/views/styles/styles.scss: -------------------------------------------------------------------------------- 1 | @import 2 | './shared', 3 | 'minx/src/reset', 4 | 'minx/src/elements', 5 | './grid'; 6 | 7 | 8 | html { 9 | overflow-y: scroll; 10 | } 11 | 12 | body { 13 | padding-bottom: 120px; 14 | } 15 | 16 | a { 17 | color: inherit; 18 | text-decoration: none; 19 | } 20 | 21 | .hide { 22 | display: none !important; 23 | } 24 | 25 | ::selection { 26 | background: rgba(200,200,255,.1); 27 | } 28 | -------------------------------------------------------------------------------- /example-project/src-php/Http/Controllers/CommentController.php: -------------------------------------------------------------------------------- 1 | = (props) => { 4 | return ( 5 |
6 | {props.children} 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /example-project/src-typescript/components/about.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { AppView } from '../layout'; 3 | 4 | export const About: React.StatelessComponent<{}> = () => { 5 | return ( 6 | 7 |
8 |

19 LoginForm

9 | 10 |
11 |

12 | This sample takes as starting point sample "18 Hooks". 13 |

14 |
15 |

16 | We are adding a login form using Material-UI. 17 |

18 |
19 |
20 | 21 |
22 |

Highlights

23 |
24 |

25 | The most interesting parts worth to take a look 26 |

27 |
28 | 29 |
30 |
    31 |
  • 32 |

    Components:

    33 |
      34 |
    • 35 |

      36 | components/login: New login page. 37 |

      38 |
    • 39 |
    • 40 |

      41 | common/components/notification: New common component to show a notification. 42 |

      43 |
    • 44 |
    45 |
  • 46 |
47 |
48 |
49 |
50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /example-project/src-typescript/components/header.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | export const Header: React.StatelessComponent<{}> = () => { 5 | return ( 6 |
7 | 8 | 27 |
28 | ); 29 | } -------------------------------------------------------------------------------- /example-project/src-typescript/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './header'; 2 | export * from './about'; 3 | export * from './members'; 4 | export * from './member'; 5 | export * from './login'; 6 | -------------------------------------------------------------------------------- /example-project/src-typescript/components/login/index.ts: -------------------------------------------------------------------------------- 1 | export { Login } from './loginPage'; 2 | -------------------------------------------------------------------------------- /example-project/src-typescript/components/login/loginForm.styles.ts: -------------------------------------------------------------------------------- 1 | import { createStyles, Theme } from "@material-ui/core/styles"; 2 | 3 | export default (theme: Theme) => createStyles({ 4 | '@global': { 5 | 'body, html, #root': { 6 | margin: 0, 7 | padding: 0, 8 | width: '100%', 9 | } 10 | }, 11 | container: { 12 | display: 'flex', 13 | flexDirection: 'column', 14 | justifyContent: 'center', 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /example-project/src-typescript/components/login/loginForm.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import TextField from '@material-ui/core/TextField'; 3 | import Button from '@material-ui/core/Button'; 4 | import { withStyles, WithStyles } from '@material-ui/core/styles'; 5 | import { LoginEntity } from '../../model'; 6 | import styles from './loginForm.styles'; 7 | 8 | interface Props extends WithStyles { 9 | onLogin: () => void; 10 | onUpdateLoginField: (name: string, value: any) => void; 11 | loginInfo: LoginEntity; 12 | } 13 | 14 | const LoginFormInner: React.StatelessComponent = (props: Props) => { 15 | 16 | const onTextFieldChange = (fieldId) => (e) => { 17 | props.onUpdateLoginField(fieldId, e.target.value); 18 | } 19 | 20 | return ( 21 |
22 | 28 | 35 | 38 |
39 | ); 40 | } 41 | 42 | export const LoginForm = withStyles(styles)(LoginFormInner); 43 | -------------------------------------------------------------------------------- /example-project/src-typescript/components/login/loginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { RouteComponentProps } from 'react-router-dom'; 3 | import { Card, CardHeader, CardContent } from '@material-ui/core'; 4 | import { LoginForm } from '@src/components/login/loginForm'; 5 | import { isValidLogin } from '../../api/login'; 6 | import { LoginEntity, createEmptyLogin } from '../../model'; 7 | import { NotificationComponent } from '../../common/components/notification'; 8 | import { CenteredView } from '../../layout'; 9 | 10 | interface Props extends RouteComponentProps { 11 | } 12 | 13 | interface State { 14 | loginInfo: LoginEntity; 15 | showLoginFailedMsg: boolean; 16 | } 17 | 18 | export class Login extends React.Component { 19 | 20 | constructor(props: Props) { 21 | super(props); 22 | 23 | this.state = { 24 | loginInfo: createEmptyLogin(), 25 | showLoginFailedMsg: false, 26 | }; 27 | } 28 | 29 | private onLogin = () => { 30 | if (isValidLogin(this.state.loginInfo)) { 31 | this.props.history.push('/about'); 32 | } else { 33 | this.setState({ 34 | ...this.state, 35 | showLoginFailedMsg: true, 36 | }); 37 | } 38 | } 39 | 40 | private onUpdateLoginField = (name, value) => { 41 | this.setState({ 42 | loginInfo: { 43 | ...this.state.loginInfo, 44 | [name]: value, 45 | }, 46 | }); 47 | } 48 | 49 | public render() { 50 | return ( 51 | 52 | this.setState({ showLoginFailedMsg: false })} 56 | /> 57 | 58 | 59 | 60 | 65 | 66 | 67 | 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /example-project/src-typescript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /example-project/src-typescript/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import { AppRouter } from './router'; 4 | 5 | ReactDOM.render( 6 | 7 | , document.getElementById('root')); 8 | -------------------------------------------------------------------------------- /example-project/src-typescript/tsConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "example-project", 4 | "moduleResolution": "node", 5 | "paths": { 6 | "@src/*": ["src-typescript/*"] 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /example-project/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* global __dirname, require, module*/ 2 | 3 | const path = require('path'); 4 | 5 | const outputFile = 'bundle.js'; 6 | 7 | const config = { 8 | entry: __dirname + '/src/index.js', 9 | output: { 10 | path: __dirname + '/dist', 11 | filename: outputFile 12 | }, 13 | module: { 14 | rules: [ ] 15 | }, 16 | resolve: { 17 | extensions: ['.js'] 18 | }, 19 | mode: 'development' 20 | }; 21 | 22 | module.exports = config; 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codecrumbs", 3 | "version": "1.8.3", 4 | "author": "Bohdan Liashenko", 5 | "license": "BSD-3-Clause", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/Bogdan-Lyashenko/codecrumbs.git" 9 | }, 10 | "scripts": { 11 | "start": "yarn client-dev & yarn server-dev", 12 | "server:one": "node src/index.dev.js", 13 | "server:two": "node src/index.dev.js two", 14 | "client-dev": "cd src/public && webpack --config webpack.dev.js --progress --colors --watch --env dev", 15 | "server-dev": "nodemon src/index.dev.js", 16 | "server:cli": "node cli/index.cli.js -e example-project/src-client/index.js -d example-project/src-client/", 17 | "server-debug": "nodemon --inspect src/index.dev.js", 18 | "clean": "rm -rf build", 19 | "webpack-compile-local": "cd src/public && webpack --config webpack.local.js --progress", 20 | "build": "yarn clean && yarn webpack-compile-local", 21 | "pretty": "prettier --write \"./src/public/js/**/*.js\"" 22 | }, 23 | "bin": { 24 | "codecrumbs": "./cli/index.cli.js" 25 | }, 26 | "dependencies": { 27 | "@babel/parser": "^7.1.2", 28 | "@babel/traverse": "^7.1.0", 29 | "antd": "^3.9.2", 30 | "chalk": "^2.4.2", 31 | "classnames": "^2.2.6", 32 | "colors": "^1.3.2", 33 | "commander": "^2.19.0", 34 | "copy-text-to-clipboard": "^1.0.4", 35 | "d3-flextree": "^2.1.1", 36 | "directory-tree": "^2.1.0", 37 | "file-saver": "^2.0.0", 38 | "http-server": "0.9.0", 39 | "js2flowchart": "1.3.2", 40 | "lodash": "^4.17.10", 41 | "lodash.debounce": "^4.0.8", 42 | "madge": "^3.4.4", 43 | "php-parser": "^3.0.2", 44 | "portscanner": "^2.2.0", 45 | "react": "^16.8.6", 46 | "react-dom": "^16.8.6", 47 | "react-redux": "^5.0.7", 48 | "react-syntax-highlighter": "8.0.1", 49 | "redux": "^4.0.0", 50 | "redux-persist": "^5.10.0", 51 | "redux-saga": "^0.16.0", 52 | "redux-thunk": "^2.2.0", 53 | "reselect": "^4.0.0", 54 | "watchpack": "^1.6.0", 55 | "websocket": "1.0.27" 56 | }, 57 | "devDependencies": { 58 | "@babel/cli": "^7.4.4", 59 | "@babel/core": "^7.1.2", 60 | "@babel/plugin-proposal-class-properties": "^7.5.0", 61 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 62 | "@babel/plugin-transform-runtime": "^7.4.4", 63 | "@babel/preset-env": "^7.1.0", 64 | "@babel/preset-react": "^7.0.0", 65 | "@commitlint/cli": "^7.3.2", 66 | "@commitlint/config-conventional": "^7.3.1", 67 | "babel-loader": "^8.0.4", 68 | "babel-plugin-import": "^1.9.1", 69 | "babel-plugin-transform-define": "^1.3.1", 70 | "css-loader": "^0.28.11", 71 | "husky": "^1.3.1", 72 | "less": "^3.9.0", 73 | "less-loader": "^5.0.0", 74 | "nodemon": "^1.18.7", 75 | "prettier": "^1.14.0", 76 | "style-loader": "^0.21.0", 77 | "webpack": "^4.20.2", 78 | "webpack-bundle-analyzer": "^3.0.3", 79 | "webpack-cli": "^3.1.2", 80 | "webpack-merge": "^4.1.5" 81 | }, 82 | "nodemonConfig": { 83 | "ignore": [ 84 | "src/public/**/*.*" 85 | ], 86 | "delay": "2500" 87 | }, 88 | "husky": { 89 | "hooks": { 90 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/index.dev.js: -------------------------------------------------------------------------------- 1 | const server = require('../src/server'); 2 | 3 | const namespaceOne = { 4 | projectNameAlias: 'todo-example-client', 5 | projectDir: `example-project/src-client`, 6 | entryPoint: `example-project/src-client/index.js`, 7 | webpackConfigPath: `example-project/webpack.config.js`, 8 | clientPort: 2018, 9 | debugModeEnabled: true 10 | }; 11 | 12 | const namespaceTwo = { 13 | projectNameAlias: 'todo-example-server', 14 | projectDir: `example-project/src-server`, 15 | entryPoint: `example-project/src-server/index.py`, 16 | clientPort: 2018 17 | }; 18 | 19 | const namespaceTypeScriptExample = { 20 | projectNameAlias: 'ts-example-server', 21 | projectDir: `example-project/src-typescript`, 22 | entryPoint: `example-project/src-typescript/index.tsx`, 23 | tsConfigPath: `example-project/src-typescript/tsConfig.json`, 24 | clientPort: 2018 25 | }; 26 | 27 | const namespacePhpExample = { 28 | projectNameAlias: 'php-example-server', 29 | projectDir: `example-project/src-php`, 30 | entryPoint: `example-project/src-php/index.php`, 31 | clientPort: 2018 32 | }; 33 | 34 | const namespaceDebug = { 35 | projectNameAlias: 'debug', 36 | projectDir: `example-project/debug`, 37 | entryPoint: `example-project/debug/index.js`, 38 | clientPort: 2018, 39 | excludeDir: 'example-project/debug/x1,example-project/debug/x2/x' 40 | }; 41 | 42 | const namespaceLanguageTest = { 43 | projectDir: `example-project/languages`, 44 | entryPoint: `example-project/languages/ruby-lang.rb`, 45 | clientPort: 2018 46 | }; 47 | 48 | const args = process.argv.slice(2); 49 | const namespaces = { 50 | two: namespaceTwo, 51 | ts: namespaceTypeScriptExample, 52 | php: namespacePhpExample 53 | }; 54 | const namespace = namespaces[args[0]] !== undefined ? namespaces[args[0]] : namespaceOne; 55 | server.setup(namespace, { isDev: true }); 56 | -------------------------------------------------------------------------------- /src/public/babel.config.js: -------------------------------------------------------------------------------- 1 | const packageJson = require('../../package'); 2 | 3 | module.exports = function(app) { 4 | app.cache(true); 5 | 6 | const presets = [ 7 | [ 8 | '@babel/preset-env', 9 | { 10 | targets: { 11 | browsers: ['last 2 versions'] 12 | }, 13 | modules: false 14 | } 15 | ], 16 | '@babel/preset-react' 17 | ]; 18 | 19 | const plugins = [ 20 | ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], 21 | '@babel/plugin-syntax-dynamic-import', 22 | '@babel/plugin-transform-runtime', 23 | '@babel/plugin-proposal-class-properties', 24 | [ 25 | 'transform-define', 26 | { 27 | 'process.env.CODECRUMBS_VERSION': packageJson.version 28 | } 29 | ] 30 | ]; 31 | 32 | return { 33 | presets, 34 | plugins 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/public/dist/local/Menlo-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/src/public/dist/local/Menlo-Regular.ttf -------------------------------------------------------------------------------- /src/public/dist/local/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodecrumbsIO/codecrumbs/31ca6f4a7831ef5d2af5a6890e8e1bab30aa726b/src/public/dist/local/favicon.ico -------------------------------------------------------------------------------- /src/public/dist/local/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Codecrumbs: better way to navigate the code maze! 7 | 15 | 16 | 17 |
18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /src/public/js/App.js: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from 'react'; 2 | 3 | import Spin from 'antd/es/spin'; 4 | import 'antd/es/spin/style'; 5 | 6 | import { isMobile } from './utils/index'; 7 | 8 | const DataBus = React.lazy(() => import(/* webpackChunkName: "data-bus" */ './core/dataBus')); 9 | const ViewsSwitches = React.lazy(() => 10 | import(/* webpackChunkName: "view-switches" */ './components/topBar/controls/ViewSwitches/ViewSwitchesContainer') 11 | ); 12 | const TopBar = React.lazy(() => 13 | import(/* webpackChunkName: "top-bar" */ './components/topBar/subPanel/SubPanelContainer') 14 | ); 15 | const TreeDiagramsContainer = React.lazy(() => 16 | import(/* webpackChunkName: "tree-diagram" */ './components/treeDiagram/TreeDiagramsContainer') 17 | ); 18 | const SideBar = React.lazy(() => 19 | import(/* webpackChunkName: "side-bar" */ './components/sideBar/SideBarContainer') 20 | ); 21 | const ExplorerBar = React.lazy(() => 22 | import(/* webpackChunkName: "explorer-bar" */ './components/explorerBar/ExplorerBarContainer') 23 | ); 24 | 25 | const Footer = React.lazy(() => import(/* webpackChunkName: "footer" */ './components/footer')); 26 | 27 | import './App.less'; 28 | 29 | const App = (props = {}) => { 30 | return ( 31 |
32 |
33 | 34 | 35 | 36 | {!isMobile ? ( 37 | }> 38 | 39 | 40 | ) : null} 41 | 42 | 43 | 44 |
45 | 46 |
47 | 48 | 49 | 50 | 53 | 54 |
55 | } 56 | > 57 | 58 | 59 | 60 | 61 | 62 |
63 | 64 |