├── public
├── robots.txt
├── favicon.ico
├── logo192.png
├── logo512.png
├── manifest.json
└── index.html
├── src
├── images
│ ├── default.jpg
│ ├── theme1.jpg
│ ├── theme2.jpg
│ ├── theme3.jpg
│ └── theme4.jpg
├── App.css
├── App.js
├── App.test.js
├── index.css
├── utils
│ └── index.js
├── index.js
├── component
│ ├── toolbar
│ │ ├── toolbar-item-open.js
│ │ ├── toolbar-item-search.js
│ │ ├── Toolbar.css
│ │ ├── toolbar-item-export.js
│ │ ├── toolbar-item-layout.js
│ │ ├── toolbar.js
│ │ └── toolbar-item-theme.js
│ └── mindmap.js
├── logo.svg
└── serviceWorker.js
├── screenshots
├── openfile.jpg
└── example-mindmap.jpg
├── config
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── pnpTs.js
├── modules.js
├── paths.js
├── env.js
├── webpackDevServer.config.js
└── webpack.config.js
├── .gitignore
├── LICENSE
├── scripts
├── test.js
├── blink.js
├── start.js
└── build.js
├── README.md
└── package.json
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/src/images/default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/src/images/default.jpg
--------------------------------------------------------------------------------
/src/images/theme1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/src/images/theme1.jpg
--------------------------------------------------------------------------------
/src/images/theme2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/src/images/theme2.jpg
--------------------------------------------------------------------------------
/src/images/theme3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/src/images/theme3.jpg
--------------------------------------------------------------------------------
/src/images/theme4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/src/images/theme4.jpg
--------------------------------------------------------------------------------
/screenshots/openfile.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/screenshots/openfile.jpg
--------------------------------------------------------------------------------
/screenshots/example-mindmap.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awehook/react-mindmap/HEAD/screenshots/example-mindmap.jpg
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .mindmap {
2 | width: 100vw;
3 | height: calc(100vh - 36px);
4 | }
5 |
6 | #root {
7 | position: fixed;
8 | left: 0;
9 | top: 0;
10 | width: 100%;
11 | height: 100%;
12 | }
13 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Mindmap from "./component/mindmap";
3 | import "./App.css";
4 |
5 | function App() {
6 | return ;
7 | }
8 |
9 | export default App;
10 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import App from "./App";
4 |
5 | it("renders without crashing", () => {
6 | const div = document.createElement("div");
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 | /build-old
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 | .idea/
26 | yarn.lock
27 |
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import { Model, createKey } from "@blink-mind/core";
2 |
3 | export const downloadFile = (url, filename) => {
4 | const link = document.createElement("a");
5 | link.href = url;
6 | link.download = filename;
7 | link.click();
8 | };
9 |
10 | export function generateSimpleModel() {
11 | const rootKey = createKey();
12 |
13 | return Model.create({
14 | rootTopicKey: rootKey,
15 | topics: [
16 | {
17 | key: rootKey,
18 | blocks: [{ type: "CONTENT", data: "MainTopic" }]
19 | }
20 | ]
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 | import * as serviceWorker from "./serviceWorker";
6 |
7 | let debugNameSpaces = [
8 | "app",
9 | // "node:*",
10 | 'plugin:layout'
11 | ];
12 |
13 | localStorage.debug = debugNameSpaces.join(",");
14 |
15 | ReactDOM.render(, document.getElementById("root"));
16 |
17 | // If you want your app to work offline and load faster, you can change
18 | // unregister() to register() below. Note this comes with some pitfalls.
19 | // Learn more about service workers: https://bit.ly/CRA-PWA
20 | serviceWorker.unregister();
21 |
--------------------------------------------------------------------------------
/src/component/toolbar/toolbar-item-open.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { iconClassName, browserOpenFile } from "@blink-mind/renderer-react";
3 |
4 | export function ToolbarItemOpen(props) {
5 | const onClickOpenFile = e => {
6 | const { diagram } = props;
7 | const diagramProps = diagram.getDiagramProps();
8 | const { controller } = diagramProps;
9 | browserOpenFile(".json,.blinkmind,.bm").then(txt => {
10 | let obj = JSON.parse(txt);
11 | let model = controller.run("deserializeModel", { controller, obj });
12 | diagram.openNewModel(model);
13 | });
14 | };
15 | return (
16 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/config/pnpTs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { resolveModuleName } = require('ts-pnp');
4 |
5 | exports.resolveModuleName = (
6 | typescript,
7 | moduleName,
8 | containingFile,
9 | compilerOptions,
10 | resolutionHost
11 | ) => {
12 | return resolveModuleName(
13 | moduleName,
14 | containingFile,
15 | compilerOptions,
16 | resolutionHost,
17 | typescript.resolveModuleName
18 | );
19 | };
20 |
21 | exports.resolveTypeReferenceDirective = (
22 | typescript,
23 | moduleName,
24 | containingFile,
25 | compilerOptions,
26 | resolutionHost
27 | ) => {
28 | return resolveModuleName(
29 | moduleName,
30 | containingFile,
31 | compilerOptions,
32 | resolutionHost,
33 | typescript.resolveTypeReferenceDirective
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/src/component/toolbar/toolbar-item-search.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { OpType } from "@blink-mind/core";
3 | import { FOCUS_MODE_SEARCH } from "@blink-mind/plugins";
4 | import { iconClassName, IconName } from "@blink-mind/renderer-react";
5 |
6 | export function ToolbarItemSearch(props) {
7 | const onClickSearch = e => {
8 | const { diagram } = props;
9 | const diagramProps = diagram.getDiagramProps();
10 | const { controller } = diagramProps;
11 |
12 | controller.run("operation", {
13 | ...diagramProps,
14 | opType: OpType.SET_FOCUS_MODE,
15 | focusMode: FOCUS_MODE_SEARCH
16 | });
17 | };
18 | return (
19 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/component/toolbar/Toolbar.css:
--------------------------------------------------------------------------------
1 | .bm-toolbar {
2 | /*padding: 5px 0;*/
3 | box-shadow: rgb(170, 170, 170) 0 0 2px;
4 | }
5 |
6 | .bm-toolbar-item {
7 | position: relative;
8 | padding: 6px;
9 | width: 40px;
10 | height: 40px;
11 | cursor: pointer;
12 | font-size: 24px;
13 | display: inline-block;
14 | }
15 |
16 | .bm-toolbar-item-disabled {
17 | color: grey;
18 | }
19 | .bm-toolbar-item-disabled:hover {
20 | color: grey !important;
21 | }
22 |
23 | .bm-toolbar-item:hover {
24 | color: rgb(44, 184, 146);
25 | }
26 |
27 | .bm-theme-item {
28 | cursor: pointer;
29 | padding: 10px;
30 | }
31 |
32 | .bm-toolbar .iconfont {
33 | font-size: 28px !important;
34 | }
35 |
36 | .bm-theme-img {
37 | width: 500px;
38 | height: 125px;
39 | border: #333333 1px solid;
40 | }
41 |
42 | .bm-theme-img:hover {
43 | border: rgb(44, 184, 146) 2px solid;
44 | }
45 |
46 | .bm-toolbar-popover-target {
47 | position: absolute;
48 | left: 0;
49 | top: 0;
50 | width: 40px;
51 | height: 40px;
52 | }
53 |
54 | .bm-popover-theme {
55 | width: auto;
56 | height: 600px;
57 | overflow: auto;
58 | }
59 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 awehook
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/component/toolbar/toolbar-item-export.js:
--------------------------------------------------------------------------------
1 | import cx from "classnames";
2 | import { iconClassName } from "@blink-mind/renderer-react";
3 | import { Menu, MenuDivider, MenuItem, Popover } from "@blueprintjs/core";
4 | import React from "react";
5 | import { downloadFile } from "../../utils";
6 |
7 | export function ToolbarItemExport(props) {
8 | const onClickExportJson = e => {
9 | const { diagram } = props;
10 | const diagramProps = diagram.getDiagramProps();
11 | const { controller, model } = diagramProps;
12 |
13 | const json = controller.run("serializeModel", diagramProps);
14 | const jsonStr = JSON.stringify(json);
15 | const url = `data:text/plain,${encodeURIComponent(jsonStr)}`;
16 | const title = controller.run("getTopicTitle", {
17 | ...diagramProps,
18 | topicKey: model.rootTopicKey
19 | });
20 | downloadFile(url, `${title}.blinkmind`);
21 | };
22 |
23 | return (
24 |
25 |
26 |
27 |
31 |
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const camelcase = require('camelcase');
5 |
6 | // This is a custom Jest transformer turning file imports into filenames.
7 | // http://facebook.github.io/jest/docs/en/webpack.html
8 |
9 | module.exports = {
10 | process(src, filename) {
11 | const assetFilename = JSON.stringify(path.basename(filename));
12 |
13 | if (filename.match(/\.svg$/)) {
14 | // Based on how SVGR generates a component name:
15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
16 | const pascalCaseFileName = camelcase(path.parse(filename).name, {
17 | pascalCase: true,
18 | });
19 | const componentName = `Svg${pascalCaseFileName}`;
20 | return `const React = require('react');
21 | module.exports = {
22 | __esModule: true,
23 | default: ${assetFilename},
24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
25 | return {
26 | $$typeof: Symbol.for('react.element'),
27 | type: 'svg',
28 | ref: ref,
29 | key: null,
30 | props: Object.assign({}, props, {
31 | children: ${assetFilename}
32 | })
33 | };
34 | }),
35 | };`;
36 | }
37 |
38 | return `module.exports = ${assetFilename};`;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/src/component/toolbar/toolbar-item-layout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { DiagramLayoutType } from "@blink-mind/core";
3 | import cx from "classnames";
4 | import { Icon, iconClassName } from "@blink-mind/renderer-react";
5 | import { Menu, MenuItem, Popover } from "@blueprintjs/core";
6 |
7 | export function ToolbarItemLayout(props) {
8 | const layoutDirs = [
9 | [
10 | DiagramLayoutType.LEFT_AND_RIGHT,
11 | "Left And Right",
12 | "layout-left-and-right"
13 | ],
14 | [DiagramLayoutType.LEFT_TO_RIGHT, "Only Right", "layout-right"],
15 | [DiagramLayoutType.RIGHT_TO_LEFT, "Only Left", "layout-left"]
16 | ];
17 |
18 | const onClickSetLayout = layoutDir => e => {
19 | const { diagram } = props;
20 | const diagramProps = diagram.getDiagramProps();
21 | const { controller } = diagramProps;
22 | controller.run("setLayoutDir", { ...diagramProps, layoutDir });
23 | };
24 |
25 | return (
26 |
29 |
30 |
31 |
41 |
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/src/component/toolbar/toolbar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import cx from "classnames";
3 | import "./Toolbar.css";
4 | import { iconClassName } from "@blink-mind/renderer-react";
5 | import { ToolbarItemOpen } from "./toolbar-item-open";
6 | import { ToolbarItemLayout } from "./toolbar-item-layout";
7 | import { ToolbarItemTheme } from "./toolbar-item-theme";
8 | import { ToolbarItemExport } from "./toolbar-item-export";
9 | import { ToolbarItemSearch } from "./toolbar-item-search";
10 |
11 | // import debug from "debug";
12 | // const log = debug("app");
13 |
14 | export class Toolbar extends React.PureComponent {
15 | render() {
16 | const props = this.props;
17 |
18 | const { onClickUndo, onClickRedo, canUndo, canRedo } = props;
19 |
20 | return (
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
34 |
35 |
41 |
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 |
19 | const jest = require('jest');
20 | const execSync = require('child_process').execSync;
21 | let argv = process.argv.slice(2);
22 |
23 | function isInGitRepository() {
24 | try {
25 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
26 | return true;
27 | } catch (e) {
28 | return false;
29 | }
30 | }
31 |
32 | function isInMercurialRepository() {
33 | try {
34 | execSync('hg --cwd . root', { stdio: 'ignore' });
35 | return true;
36 | } catch (e) {
37 | return false;
38 | }
39 | }
40 |
41 | // Watch unless on CI or explicitly running all tests
42 | if (
43 | !process.env.CI &&
44 | argv.indexOf('--watchAll') === -1 &&
45 | argv.indexOf('--watchAll=false') === -1
46 | ) {
47 | // https://github.com/facebook/create-react-app/issues/5210
48 | const hasSourceControl = isInGitRepository() || isInMercurialRepository();
49 | argv.push(hasSourceControl ? '--watch' : '--watchAll');
50 | }
51 |
52 |
53 | jest.run(argv);
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a online mindmap app using [blink-mind](https://github.com/awehook/blink-mind) library.
2 |
3 | ### Online Demo
4 |
5 | [Demo](https://awehook.github.io/react-mindmap/)
6 |
7 | [Example mind map](https://github.com/awehook/mindmap) You can download example mind maps from the repository: https://github.com/awehook/mindmap and use this app open the mind map file.
8 |
9 | 
10 |
11 |
12 | ### Features
13 |
14 | * Markdown editor for topic and topic notes.
15 |
16 | 
17 |
18 | * flowchart can be attached to topic.
19 |
20 | 
21 |
22 | 
23 |
24 | * HotKey support.
25 |
26 | 
27 |
28 | * Reorganize the diagram by drag and drop.
29 |
30 | 
31 |
32 | * Multiple theme.
33 |
34 | 
35 |
36 | * Style customization.
37 |
38 | 
39 |
40 | ### How to run
41 | ```
42 | yarn install
43 | yarn start
44 | ```
45 |
46 | Then open [localhost:3000](http://localhost:3000)
47 |
48 | 
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/component/toolbar/toolbar-item-theme.js:
--------------------------------------------------------------------------------
1 | import defaultThemeImg from "../../images/default.jpg";
2 | import theme1Img from "../../images/theme1.jpg";
3 | import theme2Img from "../../images/theme2.jpg";
4 | import theme3Img from "../../images/theme3.jpg";
5 | import theme4Img from "../../images/theme4.jpg";
6 | import cx from "classnames";
7 | import { iconClassName } from "@blink-mind/renderer-react";
8 | import { Popover } from "@blueprintjs/core";
9 | import React from "react";
10 |
11 | export function ToolbarItemTheme(props) {
12 | const onClickSetTheme = themeKey => e => {
13 | const { diagram } = props;
14 | const diagramProps = diagram.getDiagramProps();
15 | const { controller } = diagramProps;
16 | controller.run("setTheme", { ...diagramProps, themeKey });
17 | };
18 | const themes = [
19 | ["default", defaultThemeImg],
20 | ["theme1", theme1Img],
21 | ["theme2", theme2Img],
22 | ["theme3", theme3Img],
23 | ["theme4", theme4Img]
24 | ];
25 |
26 | return (
27 |
28 |
29 |
30 |
31 | {themes.map(theme => (
32 |
37 |
![{theme[0]}]({theme[1]})
38 |
39 | ))}
40 |
41 |
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/scripts/blink.js:
--------------------------------------------------------------------------------
1 | const program = require('commander');
2 | const readline = require('readline');
3 | const fs = require('fs-extra');
4 | const path = require('path');
5 | const package = require('../package.json');
6 |
7 | program.option('-u, --upgrade', 'upgrade blink-mind version');
8 | program.option('--link', 'link blink-mind');
9 | program.option('--unlink', 'unlink blink-mind');
10 |
11 | program.parse(process.argv);
12 |
13 | if (program.upgrade) {
14 | const rl = readline.createInterface({
15 | input: process.stdin,
16 | output: process.stdout
17 | });
18 |
19 | rl.question('please input the blink-mind version:', function(answer) {
20 | console.log('blink-mind version:' + answer);
21 | for (let dep in package.dependencies) {
22 | if (dep.startsWith('@blink-mind/')) package.dependencies[dep] = answer;
23 | }
24 | fs.writeJSONSync(path.resolve(__dirname, '../package.json'), package, {
25 | spaces: '\t'
26 | });
27 | rl.close();
28 | });
29 | }
30 |
31 | function getAllBlinkPackages(package) {
32 | const res = [];
33 | for (let dep in package.dependencies) {
34 | if (dep.startsWith('@blink-mind/')) {
35 | res.push(dep);
36 | }
37 | }
38 | return res;
39 | }
40 |
41 | if (program.link) {
42 | console.log('link blink-mind packages');
43 | const { exec } = require('child_process');
44 | exec(
45 | `yarn link ${getAllBlinkPackages(package).join(' ')}`,
46 | (err, stdout, stderr) => {
47 | console.log(`stdout: ${stdout}`);
48 | console.error(`stderr: ${stderr}`);
49 | if (err !== null) {
50 | console.error(`exec error: ${err}`);
51 | }
52 | }
53 | );
54 | }
55 |
56 | if (program.unlink) {
57 | console.log('link blink-mind packages');
58 | const { exec } = require('child_process');
59 | exec(
60 | `yarn unlink ${getAllBlinkPackages(package).join(' ')}`,
61 | (err, stdout, stderr) => {
62 | console.log(`stdout: ${stdout}`);
63 | stderr && console.error(`stderr: ${stderr}`);
64 | err && console.error(`exec error: ${err}`);
65 | }
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/component/mindmap.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Diagram } from "@blink-mind/renderer-react";
3 | import RichTextEditorPlugin from "@blink-mind/plugin-rich-text-editor";
4 | import { JsonSerializerPlugin } from "@blink-mind/plugin-json-serializer";
5 | import { ThemeSelectorPlugin } from "@blink-mind/plugin-theme-selector";
6 | import TopologyDiagramPlugin from "@blink-mind/plugin-topology-diagram";
7 | import { TopicReferencePlugin, SearchPlugin } from "@blink-mind/plugins";
8 | import { Toolbar } from "./toolbar/toolbar";
9 | import { generateSimpleModel } from "../utils";
10 | import "@blink-mind/renderer-react/lib/main.css";
11 | import debug from "debug";
12 |
13 | const log = debug("app");
14 |
15 | const plugins = [
16 | RichTextEditorPlugin(),
17 | ThemeSelectorPlugin(),
18 | TopicReferencePlugin(),
19 | SearchPlugin(),
20 | TopologyDiagramPlugin(),
21 | JsonSerializerPlugin()
22 | ];
23 |
24 | export class Mindmap extends React.Component {
25 | constructor(props) {
26 | super(props);
27 | this.initModel();
28 | }
29 |
30 | diagram;
31 | diagramRef = ref => {
32 | this.diagram = ref;
33 | this.setState({});
34 | };
35 |
36 | initModel() {
37 | const model = generateSimpleModel();
38 | this.state = { model };
39 | }
40 |
41 | onClickUndo = e => {
42 | const props = this.diagram.getDiagramProps();
43 | const { controller } = props;
44 | controller.run("undo", props);
45 | };
46 |
47 | onClickRedo = e => {
48 | const props = this.diagram.getDiagramProps();
49 | const { controller } = props;
50 | controller.run("redo", props);
51 | };
52 |
53 | renderDiagram() {
54 | return (
55 |
61 | );
62 | }
63 |
64 | renderToolbar() {
65 | const props = this.diagram.getDiagramProps();
66 | const { controller } = props;
67 | const canUndo = controller.run("canUndo", props);
68 | const canRedo = controller.run("canRedo", props);
69 | const toolbarProps = {
70 | diagram: this.diagram,
71 | onClickUndo: this.onClickUndo,
72 | onClickRedo: this.onClickRedo,
73 | canUndo,
74 | canRedo
75 | };
76 | return ;
77 | }
78 |
79 | onChange = (model, callback) => {
80 | this.setState(
81 | {
82 | model
83 | },
84 | callback
85 | );
86 | };
87 |
88 | render() {
89 | return (
90 |
91 | {this.diagram && this.renderToolbar()}
92 | {this.renderDiagram()}
93 |
94 | );
95 | }
96 | }
97 |
98 | export default Mindmap;
99 |
--------------------------------------------------------------------------------
/config/modules.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 | const chalk = require('react-dev-utils/chalk');
7 | const resolve = require('resolve');
8 |
9 | /**
10 | * Get the baseUrl of a compilerOptions object.
11 | *
12 | * @param {Object} options
13 | */
14 | function getAdditionalModulePaths(options = {}) {
15 | const baseUrl = options.baseUrl;
16 |
17 | // We need to explicitly check for null and undefined (and not a falsy value) because
18 | // TypeScript treats an empty string as `.`.
19 | if (baseUrl == null) {
20 | // If there's no baseUrl set we respect NODE_PATH
21 | // Note that NODE_PATH is deprecated and will be removed
22 | // in the next major release of create-react-app.
23 |
24 | const nodePath = process.env.NODE_PATH || '';
25 | return nodePath.split(path.delimiter).filter(Boolean);
26 | }
27 |
28 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
29 |
30 | // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
31 | // the default behavior.
32 | if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
33 | return null;
34 | }
35 |
36 | // Allow the user set the `baseUrl` to `appSrc`.
37 | if (path.relative(paths.appSrc, baseUrlResolved) === '') {
38 | return [paths.appSrc];
39 | }
40 |
41 | // Otherwise, throw an error.
42 | throw new Error(
43 | chalk.red.bold(
44 | "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
45 | ' Create React App does not support other values at this time.'
46 | )
47 | );
48 | }
49 |
50 | function getModules() {
51 | // Check if TypeScript is setup
52 | const hasTsConfig = fs.existsSync(paths.appTsConfig);
53 | const hasJsConfig = fs.existsSync(paths.appJsConfig);
54 |
55 | if (hasTsConfig && hasJsConfig) {
56 | throw new Error(
57 | 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
58 | );
59 | }
60 |
61 | let config;
62 |
63 | // If there's a tsconfig.json we assume it's a
64 | // TypeScript project and set up the config
65 | // based on tsconfig.json
66 | if (hasTsConfig) {
67 | const ts = require(resolve.sync('typescript', {
68 | basedir: paths.appNodeModules,
69 | }));
70 | config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
71 | // Otherwise we'll check if there is jsconfig.json
72 | // for non TS projects.
73 | } else if (hasJsConfig) {
74 | config = require(paths.appJsConfig);
75 | }
76 |
77 | config = config || {};
78 | const options = config.compilerOptions || {};
79 |
80 | const additionalModulePaths = getAdditionalModulePaths(options);
81 |
82 | return {
83 | additionalModulePaths: additionalModulePaths,
84 | hasTsConfig,
85 | };
86 | }
87 |
88 | module.exports = getModules();
89 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebook/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(inputPath, needsSlash) {
15 | const hasSlash = inputPath.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return inputPath.substr(0, inputPath.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${inputPath}/`;
20 | } else {
21 | return inputPath;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right