├── .gitignore
├── README.md
├── docs
├── css
│ ├── app.css
│ └── chunk-vendors.css
├── favicon.png
├── img
│ ├── banner-1400x560.png
│ ├── icon-128x128.png
│ ├── icon-48x48.png
│ └── logo_black.svg
├── index.html
└── js
│ ├── app.js
│ ├── app.js.map
│ ├── chunk-vendors.js
│ └── chunk-vendors.js.map
├── index.js
├── package.json
├── src
├── background.js
├── fe
│ ├── .editorconfig
│ ├── README.md
│ ├── babel.config.js
│ ├── cypress.json
│ ├── dist
│ │ ├── css
│ │ │ ├── app.css
│ │ │ └── chunk-vendors.css
│ │ ├── favicon.png
│ │ ├── index.html
│ │ └── js
│ │ │ ├── app.js
│ │ │ ├── app.js.map
│ │ │ ├── chunk-vendors.js
│ │ │ └── chunk-vendors.js.map
│ ├── package.json
│ ├── public
│ │ ├── favicon.png
│ │ └── index.html
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ ├── css
│ │ │ │ ├── reset.css
│ │ │ │ ├── style.css
│ │ │ │ └── variables.css
│ │ │ ├── img
│ │ │ │ └── arrow-left.svg
│ │ │ └── logo.png
│ │ ├── components
│ │ │ ├── Color.vue
│ │ │ ├── FooterLogo.vue
│ │ │ ├── HelloWorld.vue
│ │ │ ├── MapItem.vue
│ │ │ ├── ModalShortcuts.vue
│ │ │ ├── Node.vue
│ │ │ ├── Panno.vue
│ │ │ ├── Root.vue
│ │ │ ├── Templates.vue
│ │ │ ├── TextToolBar.vue
│ │ │ └── svg
│ │ │ │ ├── Box.vue
│ │ │ │ ├── NodeArrow.vue
│ │ │ │ └── Path.vue
│ │ ├── composables
│ │ │ ├── useAdjacency.js
│ │ │ ├── useColor.js
│ │ │ ├── useDownload.js
│ │ │ ├── useEvent.js
│ │ │ ├── useMarkdownToolbar.js
│ │ │ ├── useOnResize.js
│ │ │ ├── usePan.js
│ │ │ ├── usePanScroll.js
│ │ │ ├── useTemplates.js
│ │ │ └── useZoomWheel.js
│ │ ├── main.js
│ │ ├── map-templates
│ │ │ ├── blank.js
│ │ │ ├── emojis.js
│ │ │ └── markdown.js
│ │ ├── mock.js
│ │ ├── router
│ │ │ └── index.js
│ │ ├── utils
│ │ │ ├── api
│ │ │ │ ├── map.js
│ │ │ │ └── maps.js
│ │ │ ├── clockIndex.js
│ │ │ ├── iif.js
│ │ │ ├── isWheelRight.js
│ │ │ ├── isWheelUp.js
│ │ │ ├── mapOf.js
│ │ │ ├── wrap.js
│ │ │ └── wrapRef.js
│ │ └── views
│ │ │ ├── About.vue
│ │ │ ├── Editor.vue
│ │ │ ├── Home.vue
│ │ │ └── ToolBar.vue
│ ├── tests
│ │ ├── e2e
│ │ │ ├── .eslintrc.js
│ │ │ ├── plugins
│ │ │ │ └── index.js
│ │ │ ├── specs
│ │ │ │ └── test.js
│ │ │ └── support
│ │ │ │ ├── commands.js
│ │ │ │ └── index.js
│ │ └── unit
│ │ │ └── example.spec.js
│ └── vue.config.js
├── img
│ ├── banner-1400x560.png
│ ├── icon-128x128.png
│ ├── icon-48x48.png
│ └── logo_black.svg
└── manifest.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | /tests/e2e/videos/
6 | /tests/e2e/screenshots/
7 |
8 | # local env files
9 | .env.local
10 | .env.*.local
11 |
12 | # Log files
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | package-lock.json
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mind maps
2 |
3 | [](https://www.youtube.com/watch?v=oRwbEE5-pAc)
4 |
5 | [Use it](https://theguriev.github.io/mind-maps-ext/#/)
6 |
7 | The clear way to share complex information. Mind maps is a collaborative tool that helps you make sense of complex things.
8 | Mind maps are useful for anyone to plan, take notes, visualise information, brainstorm, solve problems, study, and share information (to name just a few). There's really no limit to their uses! Everyone who values visual thinking, in business, education, or just in their personal life can find mind maps useful to organise information.
9 |
10 | **Feature list**
11 | * Create colored Mind Maps with our add-on.
12 | * Save everything on local storage. Your mind maps will be with you in any time even without internet connection.
13 | * Export to PNG, SVG, JPG.
14 | * Keyboard shortcuts.
15 |
16 |
17 | **Social links**
18 | * [Write me](mailto:eg@beagl.in)
19 | * [Hire me](https://www.linkedin.com/in/therealguriev/)
20 | * [Like me](https://www.instagram.com/theguriev/)
21 |
--------------------------------------------------------------------------------
/docs/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/docs/favicon.png
--------------------------------------------------------------------------------
/docs/img/banner-1400x560.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/docs/img/banner-1400x560.png
--------------------------------------------------------------------------------
/docs/img/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/docs/img/icon-128x128.png
--------------------------------------------------------------------------------
/docs/img/icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/docs/img/icon-48x48.png
--------------------------------------------------------------------------------
/docs/img/logo_black.svg:
--------------------------------------------------------------------------------
1 |
79 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
Mind maps by beagl
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | console.log('')
2 | console.log('============================')
3 | console.log(' _ _ ')
4 | console.log(' | | | |')
5 | console.log(' | |__ ___ __ _ __ _| |')
6 | console.log(' | \'_ \\ / _ \\/ _` |/ _` | |')
7 | console.log(' | |_) | __/ (_| | (_| | |')
8 | console.log(' |_.__/ \\___|\\__,_|\\__, |_|')
9 | console.log(' __/ | ')
10 | console.log(' |___/ ')
11 | console.log('============================')
12 | console.log('')
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mind-maps-ext",
3 | "version": "1.0.1",
4 | "description": "The clear way to share complex information. Mind maps plugin is a collaborative mind-mapping tool that helps you make sense of complex things.",
5 | "main": "webpack.config.js",
6 | "scripts": {
7 | "build": "rm -rf dist && webpack"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/gcofficial/mind-maps-ext.git"
12 | },
13 | "keywords": [
14 | "mind",
15 | "maps",
16 | "maps",
17 | "Eugen",
18 | "Guriev",
19 | "beagl"
20 | ],
21 | "author": "Eugen Guriev ",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/gcofficial/mind-maps-ext/issues"
25 | },
26 | "homepage": "https://github.com/gcofficial/mind-maps-ext#readme",
27 | "devDependencies": {
28 | "clean-webpack-plugin": "^3.0.0",
29 | "copy-webpack-plugin": "^5.1.1",
30 | "webpack": "^4.41.5",
31 | "webpack-cli": "^3.3.10"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | chrome.browserAction.onClicked.addListener(
2 | () => {
3 | chrome.tabs.create({ url: 'index.html' })
4 | }
5 | )
--------------------------------------------------------------------------------
/src/fe/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/src/fe/README.md:
--------------------------------------------------------------------------------
1 | # beagl-mm
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | npm run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | npm run lint
26 | ```
27 |
28 | ### Run your end-to-end tests
29 | ```
30 | npm run test:e2e
31 | ```
32 |
33 | ### Run your unit tests
34 | ```
35 | npm run test:unit
36 | ```
37 |
38 | ### Customize configuration
39 | See [Configuration Reference](https://cli.vuejs.org/config/).
40 |
--------------------------------------------------------------------------------
/src/fe/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/fe/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "pluginsFile": "tests/e2e/plugins/index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/src/fe/dist/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/src/fe/dist/favicon.png
--------------------------------------------------------------------------------
/src/fe/dist/index.html:
--------------------------------------------------------------------------------
1 | Mind maps by beagl
--------------------------------------------------------------------------------
/src/fe/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mindmaps",
3 | "version": "1.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint",
9 | "test:e2e": "vue-cli-service test:e2e",
10 | "test:unit": "vue-cli-service test:unit"
11 | },
12 | "dependencies": {
13 | "@vue/composition-api": "^0.4.0",
14 | "ant-design-vue": "^1.4.12",
15 | "core-js": "^3.6.4",
16 | "dom-to-image": "^2.6.0",
17 | "lguid": "^1.0.1",
18 | "lodash": "^4.17.15",
19 | "marked": "^1.0.0",
20 | "moment": "^2.24.0",
21 | "vue": "^2.6.11",
22 | "vue-router": "^3.1.5"
23 | },
24 | "devDependencies": {
25 | "@vue/cli-plugin-babel": "^4.2.0",
26 | "@vue/cli-plugin-e2e-cypress": "^4.2.0",
27 | "@vue/cli-plugin-eslint": "^4.2.0",
28 | "@vue/cli-plugin-unit-jest": "^4.2.0",
29 | "@vue/cli-service": "^4.2.0",
30 | "@vue/eslint-config-standard": "^5.1.0",
31 | "@vue/test-utils": "1.0.0-beta.31",
32 | "babel-eslint": "^10.0.3",
33 | "eslint": "^6.7.2",
34 | "eslint-plugin-import": "^2.20.1",
35 | "eslint-plugin-node": "^11.0.0",
36 | "eslint-plugin-promise": "^4.2.1",
37 | "eslint-plugin-standard": "^4.0.0",
38 | "eslint-plugin-vue": "^6.1.2",
39 | "sass": "^1.25.0",
40 | "sass-loader": "^8.0.2",
41 | "vue-template-compiler": "^2.6.11"
42 | },
43 | "eslintConfig": {
44 | "root": true,
45 | "env": {
46 | "node": true
47 | },
48 | "extends": [
49 | "plugin:vue/essential",
50 | "@vue/standard"
51 | ],
52 | "parserOptions": {
53 | "parser": "babel-eslint"
54 | },
55 | "rules": {},
56 | "overrides": [
57 | {
58 | "files": [
59 | "**/__tests__/*.{j,t}s?(x)",
60 | "**/tests/unit/**/*.spec.{j,t}s?(x)"
61 | ],
62 | "env": {
63 | "jest": true
64 | }
65 | }
66 | ]
67 | },
68 | "browserslist": [
69 | "> 1%",
70 | "last 2 versions"
71 | ],
72 | "jest": {
73 | "preset": "@vue/cli-plugin-unit-jest"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/fe/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/src/fe/public/favicon.png
--------------------------------------------------------------------------------
/src/fe/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Mind maps by beagl
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/fe/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/src/fe/src/assets/css/reset.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, u, i, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video {
14 | margin: 0;
15 | padding: 0;
16 | border: 0;
17 | font-size: 100%;
18 | font: inherit;
19 | vertical-align: baseline;
20 | }
21 |
22 | /* make sure to set some focus styles for accessibility */
23 | :focus {
24 | outline: 0;
25 | }
26 |
27 | /* HTML5 display-role reset for older browsers */
28 | article, aside, details, figcaption, figure,
29 | footer, header, hgroup, menu, nav, section {
30 | display: block;
31 | }
32 |
33 | body {
34 | line-height: 1;
35 | }
36 |
37 | ol, ul {
38 | list-style: none;
39 | }
40 |
41 | blockquote, q {
42 | quotes: none;
43 | }
44 |
45 | blockquote:before, blockquote:after,
46 | q:before, q:after {
47 | content: '';
48 | content: none;
49 | }
50 |
51 | table {
52 | border-collapse: collapse;
53 | border-spacing: 0;
54 | }
55 |
56 | input[type=search]::-webkit-search-cancel-button,
57 | input[type=search]::-webkit-search-decoration,
58 | input[type=search]::-webkit-search-results-button,
59 | input[type=search]::-webkit-search-results-decoration {
60 | -webkit-appearance: none;
61 | -moz-appearance: none;
62 | }
63 |
64 | input[type=search] {
65 | -webkit-appearance: none;
66 | -moz-appearance: none;
67 | -webkit-box-sizing: content-box;
68 | -moz-box-sizing: content-box;
69 | box-sizing: content-box;
70 | }
71 |
72 | textarea {
73 | overflow: auto;
74 | vertical-align: top;
75 | resize: vertical;
76 | }
77 |
78 | /**
79 | * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
80 | */
81 |
82 | audio,
83 | canvas,
84 | video {
85 | display: inline-block;
86 | *display: inline;
87 | *zoom: 1;
88 | max-width: 100%;
89 | }
90 |
91 | /**
92 | * Prevent modern browsers from displaying `audio` without controls.
93 | * Remove excess height in iOS 5 devices.
94 | */
95 |
96 | audio:not([controls]) {
97 | display: none;
98 | height: 0;
99 | }
100 |
101 | /**
102 | * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.
103 | * Known issue: no IE 6 support.
104 | */
105 |
106 | [hidden] {
107 | display: none;
108 | }
109 |
110 | /**
111 | * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using
112 | * `em` units.
113 | * 2. Prevent iOS text size adjust after orientation change, without disabling
114 | * user zoom.
115 | */
116 |
117 | html {
118 | font-size: 100%; /* 1 */
119 | -webkit-text-size-adjust: 100%; /* 2 */
120 | -ms-text-size-adjust: 100%; /* 2 */
121 | }
122 |
123 | /**
124 | * Address `outline` inconsistency between Chrome and other browsers.
125 | */
126 |
127 | a:focus {
128 | outline: thin dotted;
129 | }
130 |
131 | /**
132 | * Improve readability when focused and also mouse hovered in all browsers.
133 | */
134 |
135 | a:active,
136 | a:hover {
137 | outline: 0;
138 | }
139 |
140 | /**
141 | * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.
142 | * 2. Improve image quality when scaled in IE 7.
143 | */
144 |
145 | img {
146 | border: 0; /* 1 */
147 | -ms-interpolation-mode: bicubic; /* 2 */
148 | }
149 |
150 | /**
151 | * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
152 | */
153 |
154 | figure {
155 | margin: 0;
156 | }
157 |
158 | /**
159 | * Correct margin displayed oddly in IE 6/7.
160 | */
161 |
162 | form {
163 | margin: 0;
164 | }
165 |
166 | /**
167 | * Define consistent border, margin, and padding.
168 | */
169 |
170 | fieldset {
171 | border: 1px solid #c0c0c0;
172 | margin: 0 2px;
173 | padding: 0.35em 0.625em 0.75em;
174 | }
175 |
176 | /**
177 | * 1. Correct color not being inherited in IE 6/7/8/9.
178 | * 2. Correct text not wrapping in Firefox 3.
179 | * 3. Correct alignment displayed oddly in IE 6/7.
180 | */
181 |
182 | legend {
183 | border: 0; /* 1 */
184 | padding: 0;
185 | white-space: normal; /* 2 */
186 | *margin-left: -7px; /* 3 */
187 | }
188 |
189 | /**
190 | * 1. Correct font size not being inherited in all browsers.
191 | * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,
192 | * and Chrome.
193 | * 3. Improve appearance and consistency in all browsers.
194 | */
195 |
196 | button,
197 | input,
198 | select,
199 | textarea {
200 | font-size: 100%; /* 1 */
201 | margin: 0; /* 2 */
202 | vertical-align: baseline; /* 3 */
203 | *vertical-align: middle; /* 3 */
204 | }
205 |
206 | /**
207 | * Address Firefox 3+ setting `line-height` on `input` using `!important` in
208 | * the UA stylesheet.
209 | */
210 |
211 | button,
212 | input {
213 | line-height: normal;
214 | }
215 |
216 | /**
217 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
218 | * All other form control elements do not inherit `text-transform` values.
219 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.
220 | * Correct `select` style inheritance in Firefox 4+ and Opera.
221 | */
222 |
223 | button,
224 | select {
225 | text-transform: none;
226 | }
227 |
228 | /**
229 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
230 | * and `video` controls.
231 | * 2. Correct inability to style clickable `input` types in iOS.
232 | * 3. Improve usability and consistency of cursor style between image-type
233 | * `input` and others.
234 | * 4. Remove inner spacing in IE 7 without affecting normal text inputs.
235 | * Known issue: inner spacing remains in IE 6.
236 | */
237 |
238 | button,
239 | html input[type="button"], /* 1 */
240 | input[type="reset"],
241 | input[type="submit"] {
242 | -webkit-appearance: button; /* 2 */
243 | cursor: pointer; /* 3 */
244 | *overflow: visible; /* 4 */
245 | }
246 |
247 | /**
248 | * Re-set default cursor for disabled elements.
249 | */
250 |
251 | button[disabled],
252 | html input[disabled] {
253 | cursor: default;
254 | }
255 |
256 | /**
257 | * 1. Address box sizing set to content-box in IE 8/9.
258 | * 2. Remove excess padding in IE 8/9.
259 | * 3. Remove excess padding in IE 7.
260 | * Known issue: excess padding remains in IE 6.
261 | */
262 |
263 | input[type="checkbox"],
264 | input[type="radio"] {
265 | box-sizing: border-box; /* 1 */
266 | padding: 0; /* 2 */
267 | *height: 13px; /* 3 */
268 | *width: 13px; /* 3 */
269 | }
270 |
271 | /**
272 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
273 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
274 | * (include `-moz` to future-proof).
275 | */
276 |
277 | input[type="search"] {
278 | -webkit-appearance: textfield; /* 1 */
279 | -moz-box-sizing: content-box;
280 | -webkit-box-sizing: content-box; /* 2 */
281 | box-sizing: content-box;
282 | }
283 |
284 | /**
285 | * Remove inner padding and search cancel button in Safari 5 and Chrome
286 | * on OS X.
287 | */
288 |
289 | input[type="search"]::-webkit-search-cancel-button,
290 | input[type="search"]::-webkit-search-decoration {
291 | -webkit-appearance: none;
292 | }
293 |
294 | /**
295 | * Remove inner padding and border in Firefox 3+.
296 | */
297 |
298 | button::-moz-focus-inner,
299 | input::-moz-focus-inner {
300 | border: 0;
301 | padding: 0;
302 | }
303 |
304 | /**
305 | * 1. Remove default vertical scrollbar in IE 6/7/8/9.
306 | * 2. Improve readability and alignment in all browsers.
307 | */
308 |
309 | textarea {
310 | overflow: auto; /* 1 */
311 | vertical-align: top; /* 2 */
312 | }
313 |
314 | /**
315 | * Remove most spacing between table cells.
316 | */
317 |
318 | table {
319 | border-collapse: collapse;
320 | border-spacing: 0;
321 | }
322 |
323 | html,
324 | button,
325 | input,
326 | select,
327 | textarea {
328 | color: #222;
329 | }
330 |
331 |
332 | ::-moz-selection {
333 | background: #b3d4fc;
334 | text-shadow: none;
335 | }
336 |
337 | ::selection {
338 | background: #b3d4fc;
339 | text-shadow: none;
340 | }
341 |
342 | img {
343 | vertical-align: middle;
344 | }
345 |
346 | fieldset {
347 | border: 0;
348 | margin: 0;
349 | padding: 0;
350 | }
351 |
352 | textarea {
353 | resize: vertical;
354 | }
355 |
356 | .chromeframe {
357 | margin: 0.2em 0;
358 | background: #ccc;
359 | color: #000;
360 | padding: 0.2em 0;
361 | }
--------------------------------------------------------------------------------
/src/fe/src/assets/css/variables.css:
--------------------------------------------------------------------------------
1 | :root{
2 | /* Colors */
3 | --primary: #409EFF;
4 | --success: #67C23A;
5 | --warning: #E6A23C;
6 | --danger: #F56C6C;
7 | --info: #909399;
8 | --text-primary: #303133;
9 | --text-regular: #555d66;
10 | --text-secondary: #909399;
11 | --text-placeholder: #C0C4CC;
12 | --border-base: #DCDFE6;
13 | --border-light: #E4E7ED;
14 | --border-extra-light: #F2F6FC;
15 | --white: #ffffff;
16 | --black: #000000;
17 | --background-base: #F5F7FA;
18 | --background-uploader: #fbfdff;
19 | --shadow: rgba(0, 0, 0, 0.07);
20 | --overlay: rgba(0, 0, 0, 0.5);
21 | --title-header-bg: #ebeef5;
22 |
23 | /* Margin and Padding */
24 | --space-1: .5rem;
25 | --space-2: 1rem;
26 | --space-3: 2rem;
27 | --space-4: 4rem;
28 |
29 | /* Typography */
30 |
31 | --line-height-1: 1;
32 | --line-height-2: 1.125;
33 | --line-height-3: 1.25;
34 | --line-height-4: 1.5;
35 | --caps-letter-spacing: .2em;
36 | --bold-font-weight: bold;
37 |
38 | /* Radius */
39 | --radius: 4px;
40 | }
--------------------------------------------------------------------------------
/src/fe/src/assets/img/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/fe/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/src/fe/src/assets/logo.png
--------------------------------------------------------------------------------
/src/fe/src/components/Color.vue:
--------------------------------------------------------------------------------
1 |
2 |
111 |
112 |
113 |
128 |
129 |
130 |
140 |
--------------------------------------------------------------------------------
/src/fe/src/components/FooterLogo.vue:
--------------------------------------------------------------------------------
1 |
2 |
38 |
39 |
40 |
45 |
46 |
47 |
68 |
--------------------------------------------------------------------------------
/src/fe/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |
9 |
Installed CLI Plugins
10 |
16 |
Essential Links
17 |
24 |
Ecosystem
25 |
32 |
33 |
34 |
35 |
43 |
44 |
45 |
61 |
--------------------------------------------------------------------------------
/src/fe/src/components/MapItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ map.title }}
9 |
Updated {{ fromNow }}
10 |
11 |
12 |
20 | Unstar
21 |
22 |
30 | Star
31 |
32 |
Remove
39 |
40 |
41 |
42 |
43 |
44 |
45 |
115 |
116 |
127 |
--------------------------------------------------------------------------------
/src/fe/src/components/ModalShortcuts.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 | Global
9 |
10 |
17 |
18 |
19 |
Close editing
20 |
24 |
25 |
26 |
27 |
Keyboard shortcuts
28 |
29 |
^
30 |
⌥
31 |
H
32 |
33 |
34 | Zoom
35 |
36 |
37 |
Zoom in
38 |
39 |
^
40 |
Wheel up
41 |
42 |
43 |
44 |
45 |
Zoom out
46 |
47 |
^
48 |
Wheel down
49 |
50 |
51 |
52 |
53 | Branch controls
54 |
55 |
56 |
Remove branch
57 |
58 |
⌘
59 |
Click ( on plus button )
60 |
61 |
62 |
63 |
64 | Pan
65 |
66 |
67 |
Pan up
68 |
69 |
⌘
70 |
Wheel up
71 |
72 |
73 |
74 |
75 |
Pan down
76 |
77 |
⌘
78 |
Wheel down
79 |
80 |
81 |
82 |
83 |
Pan left
84 |
85 |
⌘
86 |
Wheel left
87 |
88 |
89 |
90 |
91 |
Pan right
92 |
93 |
⌘
94 |
Wheel right
95 |
96 |
97 |
98 |
99 |
100 |
126 |
127 |
128 |
139 |
--------------------------------------------------------------------------------
/src/fe/src/components/Node.vue:
--------------------------------------------------------------------------------
1 |
2 |
74 |
75 |
76 |
213 |
214 |
550 |
--------------------------------------------------------------------------------
/src/fe/src/components/Panno.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
15 |
16 |
17 |
26 |
27 |
28 |
29 |
30 |
114 |
115 |
140 |
--------------------------------------------------------------------------------
/src/fe/src/components/Root.vue:
--------------------------------------------------------------------------------
1 |
2 |
65 |
66 |
67 |
166 |
167 |
277 |
--------------------------------------------------------------------------------
/src/fe/src/components/Templates.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Select a Template
5 |
To speed up the process, you can select from one of our pre-made templates.
6 |
10 |
11 |
12 |
13 | -
17 | {{ template.title.replace('{index}', '') }}
18 | {{ template.description }}
19 |
20 |
21 |
22 |
23 |
24 |
44 |
45 |
46 |
91 |
92 |
98 |
--------------------------------------------------------------------------------
/src/fe/src/components/TextToolBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Bold - ⌘ B
6 |
7 |
10 |
11 |
12 |
13 | Italic - ⌘ I
14 |
15 |
18 |
19 |
20 |
21 | Strikethrough - ⌘ Shift X
22 |
23 |
26 |
27 |
28 |
29 | Code - ⌘ Shift C
30 |
31 |
34 |
35 |
36 |
37 | Link - ⌘ Shift U
38 |
39 |
42 |
43 |
44 |
45 | Ordered list - ⌘ Shift 7
46 |
47 |
50 |
51 |
52 |
53 | Bulleted list - ⌘ Shift 8
54 |
55 |
58 |
59 |
60 |
61 | Blockquote - ⌘ Shift 9
62 |
63 |
66 |
67 |
68 |
69 |
70 |
120 |
121 |
122 |
154 |
--------------------------------------------------------------------------------
/src/fe/src/components/svg/Box.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
37 |
38 |
39 |
53 |
--------------------------------------------------------------------------------
/src/fe/src/components/svg/NodeArrow.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
21 |
22 |
23 |
24 |
98 |
99 |
100 |
105 |
--------------------------------------------------------------------------------
/src/fe/src/components/svg/Path.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
60 |
61 |
62 |
64 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useAdjacency.js:
--------------------------------------------------------------------------------
1 | import { ref, computed } from '@vue/composition-api'
2 | import { chain } from 'lodash'
3 | import guid from 'lguid'
4 | import mapOf from '@/utils/mapOf'
5 | import iif from '@/utils/iif'
6 |
7 | function fillId ([id, value]) {
8 | return [
9 | id,
10 | {
11 | id,
12 | ...value
13 | }
14 | ]
15 | }
16 |
17 | function fillComponent ([id, value]) {
18 | return [
19 | id,
20 | {
21 | ...value,
22 | component: value.id === 0 ? 'root' : 'node'
23 | }
24 | ]
25 | }
26 |
27 | function fillEditing ([id, value]) {
28 | return [
29 | id,
30 | {
31 | ...value,
32 | editing: value.editing === true
33 | }
34 | ]
35 | }
36 |
37 | function fillWidthHeight ([id, value]) {
38 | return [
39 | id,
40 | {
41 | ...value,
42 | width: value.width || 140,
43 | height: value.height || 32
44 | }
45 | ]
46 | }
47 |
48 | function isUpSide ({ y: fromY }, { y: toY }) {
49 | return fromY > toY
50 | }
51 |
52 | function isRightSide ({ x: fromX }, { x: toX }) {
53 | return fromX < toX
54 | }
55 |
56 | function fillSide (adjacency) {
57 | return function ([id, value]) {
58 | const from = adjacency.get(value.parent)
59 | if (from) {
60 | return [
61 | id,
62 | {
63 | ...value,
64 | isRightSide: isRightSide(from, value),
65 | isUpSide: isUpSide(from, value)
66 | }
67 | ]
68 | }
69 | return [
70 | id,
71 | {
72 | ...value
73 | }
74 | ]
75 | }
76 | }
77 |
78 | function fillHaveChildren (adjacency) {
79 | return function ([id, value]) {
80 | return [
81 | id,
82 | {
83 | ...value,
84 | isHaveChildren: children(Array.from(adjacency.values()), value.id).length > 0
85 | }
86 | ]
87 | }
88 | }
89 |
90 | /**
91 | * Get paths calculation fn.
92 | *
93 | * @param {number} index Function index. Examples:
94 | * up right | 10 + 1 = 11
95 | * up left | 10 + -1 = 9
96 | * down right | -10 + 1 = -9
97 | * down left | -10 + -1 = -11
98 | */
99 | function pathsCalculations (isRigth, from, to) {
100 | const offset = 30
101 |
102 | const xDistance = to.x - from.x
103 | const xHalf = xDistance / 2
104 |
105 | if (isRigth === true) {
106 | return {
107 | x2: from.x + xHalf + offset,
108 | y2: from.y,
109 | x3: from.x + xHalf - offset,
110 | y3: to.y
111 | }
112 | }
113 |
114 | return {
115 | x2: from.x + xHalf - offset,
116 | y2: from.y,
117 | x3: from.x + xHalf + offset,
118 | y3: to.y
119 | }
120 | }
121 |
122 | function createPath (list) {
123 | return function ([id, to]) {
124 | const from = list.get(to.parent)
125 | const newId = `${id}-${to.id}`
126 |
127 | const points23 = pathsCalculations(isRightSide(from, to), from, to)
128 |
129 | return [
130 | newId,
131 | {
132 | id: newId,
133 | fromID: id,
134 | toID: to.id,
135 | x: from.x,
136 | y: from.y,
137 | x2: points23.x2,
138 | y2: points23.y2,
139 | x3: points23.x3,
140 | y3: points23.y3,
141 | x4: to.x,
142 | y4: to.y,
143 | isRightSide: isRightSide(from, to),
144 | strokeWidth: 6,
145 | stroke: to.stroke || 'black'
146 | }
147 | ]
148 | }
149 | }
150 |
151 | function prepareList (adjacency) {
152 | return chain(adjacency.value)
153 | .thru(Array.from)
154 | .map(fillId)
155 | .map(fillComponent)
156 | .map(fillEditing)
157 | .map(fillWidthHeight)
158 | .map(fillSide(adjacency.value))
159 | .map(fillHaveChildren(adjacency.value))
160 | .thru(mapOf)
161 | .value()
162 | }
163 |
164 | function preparePaths (list) {
165 | return chain(list.value)
166 | .thru(Array.from)
167 | .map(
168 | iif(
169 | ([id, value]) => value.parent !== undefined,
170 | createPath(list.value),
171 | undefined
172 | )
173 | )
174 | .filter(el => el)
175 | .thru(mapOf)
176 | .value()
177 | }
178 |
179 | function getNewPosition (index = 1, pieces = 9, distance = 200) {
180 | let offset = 0
181 | if (index >= pieces) {
182 | offset = Math.floor(index / pieces) * 0.03
183 | }
184 | const pi = ((2 * Math.PI / pieces) + offset) * (index - 2)
185 | return {
186 | x: +Math.cos(pi).toFixed(2) * distance,
187 | y: +Math.sin(pi).toFixed(2) * distance
188 | }
189 | }
190 |
191 | function children (arr, parent) {
192 | return arr.filter(el => el.parent === parent)
193 | }
194 |
195 | function branch (arr, parent) {
196 | const test = arr.filter(el => el.parent === parent)
197 | const test2 = test.reduce(
198 | (acc, el) => ([...acc, el, ...branch(arr, el.id)]),
199 | []
200 | )
201 | return test2
202 | }
203 |
204 | export default function (map) {
205 | const adjacency = ref(map)
206 | const list = computed(() => prepareList(adjacency))
207 | const paths = computed(() => preparePaths(list))
208 |
209 | function add (parentID, offsetIndex) {
210 | const parent = adjacency.value.get(parentID)
211 | const index = children(Array.from(adjacency.value.values()), parentID).length
212 | const newPosition = getNewPosition(index + offsetIndex)
213 |
214 | const x = parent.x + newPosition.x
215 | const y = parent.y + newPosition.y
216 |
217 | adjacency.value.set(
218 | guid(),
219 | {
220 | name: '',
221 | x,
222 | y,
223 | parent: parentID,
224 | stroke: parent.stroke
225 | }
226 | )
227 | adjacency.value = new Map(adjacency.value.entries())
228 | return adjacency
229 | }
230 |
231 | function remove (id) {
232 | const old = list.value.get(id)
233 | chain(Array.from(list.value.values()))
234 | .thru(arr => branch(arr, id))
235 | .concat(old)
236 | .forEach(
237 | el => {
238 | adjacency.value.delete(el.id)
239 | }
240 | )
241 | .value()
242 | adjacency.value = new Map(adjacency.value.entries())
243 | return adjacency
244 | }
245 |
246 | function updatePosition (node) {
247 | const old = list.value.get(node.id)
248 | const offsetX = old.x - node.x
249 | const offsetY = old.y - node.y
250 |
251 | chain(Array.from(list.value.values()))
252 | .thru(arr => branch(arr, node.id))
253 | .concat(old)
254 | .map(
255 | el => ({
256 | ...el,
257 | x: el.x - offsetX,
258 | y: el.y - offsetY
259 | })
260 | )
261 | .forEach(
262 | el => {
263 | adjacency.value.set(el.id, el)
264 | }
265 | )
266 | .value()
267 |
268 | adjacency.value = new Map(adjacency.value.entries())
269 | return adjacency
270 | }
271 |
272 | function update (node) {
273 | adjacency.value.set(node.id, node)
274 | adjacency.value = new Map(adjacency.value.entries())
275 | return adjacency
276 | }
277 |
278 | function updateBranch (id, newData) {
279 | const old = list.value.get(id)
280 | chain(Array.from(list.value.values()))
281 | .thru(arr => branch(arr, id))
282 | .concat(old)
283 | .map(
284 | el => ({
285 | ...el,
286 | ...newData
287 | })
288 | )
289 | .forEach(
290 | el => {
291 | adjacency.value.set(el.id, el)
292 | }
293 | )
294 | .value()
295 |
296 | adjacency.value = new Map(adjacency.value.entries())
297 | return adjacency
298 | }
299 |
300 | return {
301 | adjacency,
302 | list,
303 | paths,
304 | add,
305 | updatePosition,
306 | update,
307 | updateBranch,
308 | remove
309 | }
310 | }
311 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useColor.js:
--------------------------------------------------------------------------------
1 | import { ref } from '@vue/composition-api'
2 | import useEvent from './useEvent'
3 |
4 | export default function () {
5 | const visible = ref(null)
6 | const x = ref(0)
7 | const y = ref(0)
8 |
9 | function pathClick (path, event) {
10 | visible.value = path
11 | x.value = event.clientX
12 | y.value = event.clientY
13 | }
14 |
15 | function clickOutsideColor (event) {
16 | if (visible.value !== null) {
17 | visible.value = null
18 | }
19 | }
20 |
21 | useEvent(window, 'click', clickOutsideColor)
22 |
23 | return {
24 | visible,
25 | x,
26 | y,
27 | pathClick
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useDownload.js:
--------------------------------------------------------------------------------
1 | import domtoimage from 'dom-to-image'
2 |
3 | export default function (dom) {
4 | function generateDownload (ext) {
5 | return function (dataUrl) {
6 | const link = document.createElement('a')
7 | link.download = `download.${ext}`
8 | link.href = dataUrl
9 | link.click()
10 | }
11 | }
12 |
13 | function saveSvg () {
14 | domtoimage.toSvg(dom.value.$el).then(generateDownload('svg'))
15 | }
16 |
17 | function savePng () {
18 | domtoimage.toPng(dom.value.$el).then(generateDownload('png'))
19 | }
20 |
21 | function saveJpeg () {
22 | domtoimage.toJpeg(dom.value.$el).then(generateDownload('jpg'))
23 | }
24 |
25 | return {
26 | saveSvg,
27 | savePng,
28 | saveJpeg
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useEvent.js:
--------------------------------------------------------------------------------
1 | import { watch } from '@vue/composition-api'
2 | import wrapRef from '@/utils/wrapRef'
3 |
4 | export default function (el, name, listener, options) {
5 | const element = wrapRef(el)
6 |
7 | watch(
8 | element,
9 | (newVal, _oldVal, onCleanup) => {
10 | newVal && newVal.addEventListener(name, listener, options)
11 | onCleanup(() => newVal && newVal.removeEventListener(name, listener))
12 | }
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useMarkdownToolbar.js:
--------------------------------------------------------------------------------
1 | import { wrap } from '@/utils/wrap'
2 |
3 | export default function (textarea) {
4 | function textareaWrap (wherewith) {
5 | const dom = textarea.value
6 | const { str, start, end } = wrap(dom.value, dom.selectionStart, dom.selectionEnd, wherewith)
7 | dom.value = str
8 | dom.focus()
9 | dom.setSelectionRange(start, end)
10 | dom.dispatchEvent(
11 | new Event(
12 | 'input',
13 | {
14 | bubbles: true,
15 | cancelable: true
16 | }
17 | )
18 | )
19 | }
20 |
21 | function textareaLists (itemFn, offset) {
22 | const dom = textarea.value
23 | const start = dom.selectionStart
24 | const end = dom.selectionEnd
25 | const newVal = dom.value
26 | .substr(start, end)
27 | .split(String.fromCharCode(10))
28 | .map(itemFn)
29 | .join(String.fromCharCode(10))
30 | const endOffset = dom.value
31 | .substr(start, end)
32 | .split(String.fromCharCode(10))
33 | .length * offset
34 |
35 | dom.value = dom.value.substr(0, start) + newVal + dom.value.substr(end, dom.value.length)
36 | dom.focus()
37 | dom.setSelectionRange(start, end + endOffset)
38 | dom.dispatchEvent(
39 | new Event(
40 | 'input',
41 | {
42 | bubbles: true,
43 | cancelable: true
44 | }
45 | )
46 | )
47 | }
48 |
49 | function bold () {
50 | textareaWrap('**')
51 | }
52 |
53 | function italic () {
54 | textareaWrap('_')
55 | }
56 |
57 | function strikethrough () {
58 | textareaWrap('~~')
59 | }
60 |
61 | function code () {
62 | textareaWrap('```')
63 | }
64 |
65 | function link () {
66 | const dom = textarea.value
67 | const start = dom.selectionStart
68 | const end = dom.selectionEnd
69 | dom.value = dom.value.substring(0, start) + '[' + dom.value.substr(start, end) + ']' + '(http://beagl.in)'
70 | dom.focus()
71 | dom.setSelectionRange(start + 1, end + 1)
72 | dom.dispatchEvent(
73 | new Event(
74 | 'input',
75 | {
76 | bubbles: true,
77 | cancelable: true
78 | }
79 | )
80 | )
81 | }
82 |
83 | function orderedList () {
84 | textareaLists(
85 | (line, index) => `${index + 1}. ${line}`,
86 | 3
87 | )
88 | }
89 | function bulletedList () {
90 | textareaLists(
91 | (line, index) => `* ${line}`,
92 | 2
93 | )
94 | }
95 |
96 | function blockquote () {
97 | textareaLists(
98 | (line, index) => `> ${line}`,
99 | 2
100 | )
101 | }
102 |
103 | return {
104 | textareaWrap,
105 | textareaLists,
106 | bold,
107 | italic,
108 | strikethrough,
109 | code,
110 | link,
111 | orderedList,
112 | bulletedList,
113 | blockquote
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useOnResize.js:
--------------------------------------------------------------------------------
1 | import { debounce } from 'lodash'
2 | import { onMounted, onUnmounted, ref } from '@vue/composition-api'
3 | import wrapRef from '@/utils/wrapRef'
4 |
5 | function getUpdater (el, width, height) {
6 | if (el !== window) {
7 | const elRef = wrapRef(el)
8 | const dom = elRef.value.$el instanceof HTMLElement ? elRef.value.$el : elRef.value
9 |
10 | return function () {
11 | width.value = dom.offsetWidth
12 | height.value = dom.offsetHeight
13 | }
14 | }
15 | return function () {
16 | width.value = window.innerWidth
17 | height.value = window.innerHeight
18 | }
19 | }
20 |
21 | export default function (el = window, options, wait = 0) {
22 | const width = ref(0)
23 | const height = ref(0)
24 | const remove = ref(() => {})
25 | const handler = ref(() => {})
26 |
27 | onMounted(() => {
28 | const update = getUpdater(el, width, height)
29 | handler.value = wait > 0 ? debounce(update, wait) : update
30 | window.addEventListener('resize', handler.value, options || { passive: true })
31 | update()
32 | })
33 |
34 | onUnmounted(() => {
35 | window.removeEventListener('resize', handler.value)
36 | })
37 |
38 | return {
39 | height,
40 | width,
41 | remove
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/fe/src/composables/usePan.js:
--------------------------------------------------------------------------------
1 | import { ref } from '@vue/composition-api'
2 |
3 | export default function ({ visibilityArea, offsetX, offsetY, node, scale, zoomArea }, emit) {
4 | const x = ref(0)
5 | const y = ref(0)
6 | const paning = ref(false)
7 |
8 | function startPan (event) {
9 | paning.value = true
10 | x.value = event.clientX - visibilityArea.value.getBoundingClientRect().x
11 | y.value = event.clientY - visibilityArea.value.getBoundingClientRect().y
12 | x.value -= offsetX.value
13 | y.value -= offsetY.value
14 | }
15 |
16 | function pan (event) {
17 | if (paning.value === true) {
18 | offsetX.value = event.clientX - visibilityArea.value.getBoundingClientRect().x - x.value
19 | offsetY.value = event.clientY - visibilityArea.value.getBoundingClientRect().y - y.value
20 | }
21 | if (node.value) {
22 | emit(
23 | 'updateNodePosition',
24 | {
25 | ...node.value,
26 | x: (event.clientX - zoomArea.value.getBoundingClientRect().x) / scale.value - node.value.offsetX,
27 | y: (event.clientY - zoomArea.value.getBoundingClientRect().y) / scale.value - node.value.offsetY
28 | }
29 | )
30 | }
31 | }
32 |
33 | function endPan () {
34 | paning.value = false
35 | emit('mouseup')
36 | }
37 |
38 | return {
39 | startPan,
40 | pan,
41 | endPan,
42 | offsetX,
43 | offsetY,
44 | paning,
45 | visibilityArea
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/fe/src/composables/usePanScroll.js:
--------------------------------------------------------------------------------
1 | import { identity } from 'lodash'
2 | import useEvent from '@/composables/useEvent'
3 | import isWheelUp from '@/utils/isWheelUp'
4 | import isWheelRight from '@/utils/isWheelRight'
5 |
6 | export default function ({ visibilityArea, offsetX, offsetY }) {
7 | function scroll (event) {
8 | const step = 10
9 |
10 | function up () {
11 | offsetY.value = offsetY.value - step
12 | }
13 |
14 | function down () {
15 | offsetY.value = offsetY.value + step
16 | }
17 |
18 | function left () {
19 | offsetX.value = offsetX.value - step
20 | }
21 |
22 | function right () {
23 | offsetX.value = offsetX.value + step
24 | }
25 |
26 | if (event.ctrlKey === false && event.altKey === false && event.shiftKey === false && event.metaKey === true) {
27 | const actionsMap = new Map([
28 | [1, up],
29 | [-1, down],
30 | [0, identity],
31 | [11, right],
32 | [9, left],
33 | [10, identity]
34 | ])
35 |
36 | actionsMap.get(isWheelUp(event))(event)
37 | actionsMap.get(10 + isWheelRight(event))(event)
38 | event.stopPropagation()
39 | event.preventDefault()
40 | }
41 | }
42 |
43 | useEvent(visibilityArea, 'wheel', scroll, { passive: false })
44 | }
45 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useTemplates.js:
--------------------------------------------------------------------------------
1 | import { get, omit } from 'lodash'
2 | import { computed } from '@vue/composition-api'
3 | import blank from '@/map-templates/blank'
4 | import markdown from '@/map-templates/markdown'
5 | import emojis from '@/map-templates/emojis'
6 |
7 | export default function (maps) {
8 | function prepareTemplate (template, { centerX, centerY }, index) {
9 | const root = { ...template.content[0][1] }
10 | const offsetX = centerX - root.x
11 | const offsetY = centerY - root.y
12 |
13 | template.content = template.content.map(
14 | ([id, node]) => ([
15 | id,
16 | {
17 | ...node,
18 | x: node.x + offsetX,
19 | y: node.y + offsetY
20 | }
21 | ])
22 | )
23 | template.content[0][1].name = template.content[0][1].name.replace('{index}', index)
24 |
25 | return {
26 | ...template,
27 | title: template.content[0][1].name
28 | }
29 | }
30 |
31 | const templates = computed(
32 | () => ([
33 | blank,
34 | markdown,
35 | emojis
36 | ].concat(
37 | get(maps, 'value', [])
38 | .filter(
39 | el => get(el, 'meta.template.0', '0') === '1'
40 | ).map(
41 | el => ({
42 | ...el,
43 | description: 'Custom template'
44 | })
45 | )
46 | ).map(
47 | el => omit(el, ['id', 'date', 'modified'])
48 | ))
49 | )
50 |
51 | return {
52 | templates,
53 | prepareTemplate
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/fe/src/composables/useZoomWheel.js:
--------------------------------------------------------------------------------
1 | import { ref } from '@vue/composition-api'
2 | import useEvent from '@/composables/useEvent'
3 | import isWheelUp from '@/utils/isWheelUp'
4 |
5 | export default function (visibilityArea, maxZoom = 10, zoomStep = 0.05, minZoom = 0.25) {
6 | const scale = ref(1)
7 | const cursorX = ref(0)
8 | const cursorY = ref(0)
9 | const offsetX = ref(0)
10 | const offsetY = ref(0)
11 |
12 | function increase () {
13 | const newScale = scale.value + scale.value * zoomStep
14 | if (maxZoom > newScale) {
15 | offsetX.value = cursorX.value * zoomStep * -1 + (offsetX.value * (zoomStep + 1))
16 | offsetY.value = cursorY.value * zoomStep * -1 + (offsetY.value * (zoomStep + 1))
17 | scale.value = newScale
18 | }
19 | }
20 |
21 | function decrease () {
22 | const newScale = scale.value - scale.value * zoomStep
23 | if (minZoom < newScale) {
24 | offsetX.value = cursorX.value - cursorX.value * (1 - zoomStep) + (offsetX.value * (1 - zoomStep))
25 | offsetY.value = cursorY.value - cursorY.value * (1 - zoomStep) + (offsetY.value * (1 - zoomStep))
26 | scale.value -= scale.value * zoomStep
27 | }
28 | }
29 |
30 | function wheel (event) {
31 | if (event.ctrlKey) {
32 | const actionsMap = new Map([
33 | [1, increase],
34 | [-1, decrease],
35 | [0, () => {}]
36 | ])
37 | cursorX.value = event.clientX - visibilityArea.value.getBoundingClientRect().x
38 | cursorY.value = event.clientY - visibilityArea.value.getBoundingClientRect().y
39 | actionsMap.get(isWheelUp(event))()
40 | event.preventDefault()
41 | event.stopPropagation()
42 | }
43 | }
44 |
45 | const removeWheelListener = useEvent(visibilityArea, 'wheel', wheel, { passive: false })
46 |
47 | return {
48 | scale,
49 | cursorX,
50 | cursorY,
51 | offsetX,
52 | offsetY,
53 | removeWheelListener
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/fe/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Antd from 'ant-design-vue'
3 | import VueCompositionApi from '@vue/composition-api'
4 | import App from './App.vue'
5 | import router from './router'
6 | import './mock'
7 | import 'ant-design-vue/dist/antd.css'
8 | import '@/assets/css/reset.css'
9 | import '@/assets/css/variables.css'
10 | import '@/assets/css/style.css'
11 |
12 | Vue.config.productionTip = false
13 | Vue.use(Antd)
14 | Vue.use(VueCompositionApi)
15 |
16 | const vue = new Vue({
17 | router,
18 | render: h => h(App)
19 | }).$mount('#mmb')
20 |
21 | /** Important debug notifications */
22 | window.mmb.notify = vue.$notification.error
23 |
--------------------------------------------------------------------------------
/src/fe/src/map-templates/blank.js:
--------------------------------------------------------------------------------
1 | export default {
2 | title: 'Blank map',
3 | description: 'The blank map allows you to create any type of map using our drag & drop builder.',
4 | content: [
5 | [
6 | 0,
7 | {
8 | name: 'Mind maps by Beagl {index}',
9 | x: 0,
10 | y: 0
11 | }
12 | ]
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/src/fe/src/map-templates/emojis.js:
--------------------------------------------------------------------------------
1 | export default {
2 | id: 54,
3 | title: 'Emojis ❤️ {index}',
4 | description: 'All possible emojis.',
5 | content: [
6 | [
7 | 0,
8 | {
9 | id: 0,
10 | name: 'Emojis ❤️ {index}',
11 | x: 872.5,
12 | y: 669,
13 | component: 'root',
14 | editing: false,
15 | width: 140,
16 | height: 32,
17 | isHaveChildren: true
18 | }
19 | ],
20 | [
21 | 'd3bda213-ed91-2f80-ac87-b6760f932277',
22 | {
23 | id: 'd3bda213-ed91-2f80-ac87-b6760f932277',
24 | name: '## Smileys\n\n😀 😁 😂 🤣 😃 😄 😅 😆 😉 😊 😋 😎 😍 😘 🥰 😗 \n😙 😚 🙂 🤗 🤩 🤔 🤨 😐 😑 😶 🙄 😏 😣 😥 😮 🤐 \n😯 😪 😫 😴 😌 😛 😜 😝 🤤 😒 😓 😔 😕 🙃 🤑 😲 \n🙁 😖 😞 😟 😤 😢 😭 😦 😧 😨 😩 🤯 😬 😰 😱 🥵 \n🥶 😳 🤪 😵 😡 😠 🤬 😷 🤒 🤕 🤢 🤮 🤧 😇 🤠 🤡 \n🥳 🥴 🥺 🤥 🤫 🤭 🧐 🤓 😈 👿 👹 👺 💀 👻 👽 🤖 \n💩 😺 😸 😹 😻 😼 😽 🙀 😿 😾',
25 | x: 1171.5,
26 | y: 450,
27 | parent: 0,
28 | stroke: '#F22E9A',
29 | component: 'node',
30 | editing: false,
31 | width: 429.5,
32 | height: 322.0625,
33 | isRightSide: true,
34 | isUpSide: true,
35 | isHaveChildren: false
36 | }
37 | ],
38 | [
39 | '0e33718e-93c7-e474-ef97-b301ffac54df',
40 | {
41 | id: '0e33718e-93c7-e474-ef97-b301ffac54df',
42 | name: '## People and Fantasy\n\n👶 👧 🧒 👦 👩 🧑 👨 👵 🧓 👴 👲 👳\u200d♀️ 👳\u200d♂️ 🧕\n 🧔 👱\u200d♂️ 👱\u200d♀️ 👨\u200d🦰 👩\u200d🦰 👨\u200d🦱 👩\u200d🦱 👨\u200d🦲 👩\u200d🦲 👨\u200d🦳 👩\u200d🦳 🦸\u200d♀️ 🦸\u200d♂️ 🦹\u200d♀️ \n🦹\u200d♂️ 👮\u200d♀️ 👮\u200d♂️ 👷\u200d♀️ 👷\u200d♂️ 💂\u200d♀️ 💂\u200d♂️ 🕵️\u200d♀️ 🕵️\u200d♂️ 👩\u200d⚕️ 👨\u200d⚕️ 👩\u200d🌾 👨\u200d🌾 👩\u200d🍳 \n👨\u200d🍳 👩\u200d🎓 👨\u200d🎓 👩\u200d🎤 👨\u200d🎤 👩\u200d🏫 👨\u200d🏫 👩\u200d🏭 👨\u200d🏭 👩\u200d💻 👨\u200d💻 👩\u200d💼 👨\u200d💼 👩\u200d🔧 \n👨\u200d🔧 👩\u200d🔬 👨\u200d🔬 👩\u200d🎨 👨\u200d🎨 👩\u200d🚒 👨\u200d🚒 👩\u200d✈️ 👨\u200d✈️ 👩\u200d🚀 👨\u200d🚀 👩\u200d⚖️ 👨\u200d⚖️ 👰 \n🤵 👸 🤴 🤶 🎅 🧙\u200d♀️ 🧙\u200d♂️ 🧝\u200d♀️ 🧝\u200d♂️ 🧛\u200d♀️ 🧛\u200d♂️ 🧟\u200d♀️ 🧟\u200d♂️ 🧞\u200d♀️ \n🧞\u200d♂️ 🧜\u200d♀️ 🧜\u200d♂️ 🧚\u200d♀️ 🧚\u200d♂️ 👼 🤰 🤱 🙇\u200d♀️ 🙇\u200d♂️ 💁\u200d♀️ 💁\u200d♂️ 🙅\u200d♀️ 🙅\u200d♂️ \n🙆\u200d♀️ 🙆\u200d♂️ 🙋\u200d♀️ 🙋\u200d♂️ 🤦\u200d♀️ 🤦\u200d♂️ 🤷\u200d♀️ 🤷\u200d♂️ 🙎\u200d♀️ 🙎\u200d♂️ 🙍\u200d♀️ 🙍\u200d♂️ 💇\u200d♀️ 💇\u200d♂️ \n💆\u200d♀️ 💆\u200d♂️ 🧖\u200d♀️ 🧖\u200d♂️ 💅 🤳 💃 🕺 👯\u200d♀️ 👯\u200d♂️ 🕴 🚶\u200d♀️ 🚶\u200d♂️ 🏃\u200d♀️ \n🏃\u200d♂️ 👫 👭 👬 💑 👩\u200d❤️\u200d👩 👨\u200d❤️\u200d👨 💏 👩\u200d❤️\u200d💋\u200d👩 👨\u200d❤️\u200d💋\u200d👨 👪 👨\u200d👩\u200d👧 👨\u200d👩\u200d👧\u200d👦 👨\u200d👩\u200d👦\u200d👦 \n👨\u200d👩\u200d👧\u200d👧 👩\u200d👩\u200d👦 👩\u200d👩\u200d👧 👩\u200d👩\u200d👧\u200d👦 👩\u200d👩\u200d👦\u200d👦 👩\u200d👩\u200d👧\u200d👧 👨\u200d👨\u200d👦 👨\u200d👨\u200d👧 👨\u200d👨\u200d👧\u200d👦 👨\u200d👨\u200d👦\u200d👦 👨\u200d👨\u200d👧\u200d👧 👩\u200d👦 👩\u200d👧 👩\u200d👧\u200d👦 \n👩\u200d👦\u200d👦 👩\u200d👧\u200d👧 👨\u200d👦 👨\u200d👧 👨\u200d👧\u200d👦 👨\u200d👦\u200d👦 👨\u200d👧\u200d👧 🤲 👐 🙌 👏 🤝 👍 👎 \n👊 ✊ 🤛 🤜 🤞 ✌️ 🤟 🤘 👌 👈 👉 👆 👇 ☝️ \n✋ 🤚 🖐 🖖 👋 🤙 💪 🦵 🦶 🖕 ✍️ 🙏 💍 💄 \n💋 👄 👅 👂 👃 👣 👁 👀 🧠 🦴 🦷 🗣 👤 👥',
43 | x: 1177.5,
44 | y: 794,
45 | parent: 0,
46 | stroke: '#59C1D9',
47 | component: 'node',
48 | editing: false,
49 | width: 373.5,
50 | height: 330.59375,
51 | isRightSide: true,
52 | isUpSide: false,
53 | isHaveChildren: false
54 | }
55 | ],
56 | [
57 | '8ac8b449-2e70-cbba-45ce-53450cef756e',
58 | {
59 | id: '8ac8b449-2e70-cbba-45ce-53450cef756e',
60 | name: '## Clothing and Accessories\n\n🧥 👚 👕 👖 👔 👗 👙 👘 👠 \n👡 👢👞👟 🥾 🥿 🧦 🧤 🧣 🎩 🧢 👒 🎓 \n⛑ 👑 👝 👛 👜 💼 🎒 👓 🕶 🥽 🥼 \n🌂 🧵 🧶',
61 | x: 723.5,
62 | y: 898,
63 | parent: 0,
64 | stroke: '#F23005',
65 | component: 'node',
66 | editing: false,
67 | width: 329.5,
68 | height: 263.9921875,
69 | isRightSide: false,
70 | isUpSide: false,
71 | isHaveChildren: false
72 | }
73 | ],
74 | [
75 | 'ec513d57-504d-5491-8b15-52e7061eee83',
76 | {
77 | id: 'ec513d57-504d-5491-8b15-52e7061eee83',
78 | name: '## Emojis\n\n👶🏻 👦🏻 👧🏻 👨🏻 👩🏻 👱🏻\u200d♀️ 👱🏻 👴🏻 👵🏻 👲🏻 👳🏻\u200d♀️ 👳🏻 👮🏻\u200d♀️ 👮🏻 👷🏻\u200d♀️ \n👷🏻 💂🏻\u200d♀️ 💂🏻 🕵🏻\u200d♀️ 🕵🏻 👩🏻\u200d⚕️ 👨🏻\u200d⚕️ 👩🏻\u200d🌾 👨🏻\u200d🌾 👩🏻\u200d🍳 👨🏻\u200d🍳 👩🏻\u200d🎓 👨🏻\u200d🎓 👩🏻\u200d🎤 👨🏻\u200d🎤 \n👩🏻\u200d🏫 👨🏻\u200d🏫 👩🏻\u200d🏭 👨🏻\u200d🏭 👩🏻\u200d💻 👨🏻\u200d💻 👩🏻\u200d💼 👨🏻\u200d💼 👩🏻\u200d🔧 👨🏻\u200d🔧 👩🏻\u200d🔬 👨🏻\u200d🔬 👩🏻\u200d🎨 👨🏻\u200d🎨 👩🏻\u200d🚒 \n👨🏻\u200d🚒 👩🏻\u200d✈️ 👨🏻\u200d✈️ 👩🏻\u200d🚀 👨🏻\u200d🚀 👩🏻\u200d⚖️ 👨🏻\u200d⚖️ 🤶🏻 🎅🏻 👸🏻 🤴🏻 👰🏻 🤵🏻 👼🏻 🤰🏻 \n🙇🏻\u200d♀️ 🙇🏻 💁🏻 💁🏻\u200d♂️ 🙅🏻 🙅🏻\u200d♂️ 🙆🏻 🙆🏻\u200d♂️ 🙋🏻 🙋🏻\u200d♂️ 🤦🏻\u200d♀️ 🤦🏻\u200d♂️ 🤷🏻\u200d♀️ 🤷🏻\u200d♂️ 🙎🏻 \n🙎🏻\u200d♂️ 🙍🏻 🙍🏻\u200d♂️ 💇🏻 💇🏻\u200d♂️ 💆🏻 💆🏻\u200d♂️ 🕴🏻 💃🏻 🕺🏻 🚶🏻\u200d♀️ 🚶🏻 🏃🏻\u200d♀️ 🏃🏻 🤲🏻 \n👐🏻 🙌🏻 👏🏻 🙏🏻 👍🏻 👎🏻 👊🏻 ✊🏻 🤛🏻 🤜🏻 🤞🏻 ✌🏻 🤟🏻 🤘🏻 👌🏻 \n👈🏻 👉🏻 👆🏻 👇🏻 ☝🏻 ✋🏻 🤚🏻 🖐🏻 🖖🏻 👋🏻 🤙🏻 💪🏻 🖕🏻 ✍🏻 🤳🏻 \n💅🏻 👂🏻 👃🏻',
79 | x: 635.5,
80 | y: 606,
81 | parent: 0,
82 | stroke: '#038C65',
83 | component: 'node',
84 | editing: false,
85 | width: 386.5,
86 | height: 505.0703125,
87 | isRightSide: false,
88 | isUpSide: true,
89 | isHaveChildren: false
90 | }
91 | ],
92 | [
93 | 'dc90d6cb-e7ad-b3a6-0b44-eaf572979fc3',
94 | {
95 | id: 'dc90d6cb-e7ad-b3a6-0b44-eaf572979fc3',
96 | name: '## Animals & Nature\n\n🐶 🐱 🐭 🐹 🐰 🦊 🦝 🐻 🐼 🦘 🦡 🐨 🐯 🦁 \n🐮 🐷 🐽 🐸 🐵 🙈 🙉 🙊 🐒 🐔 🐧 🐦 🐤 🐣 \n🐥 🦆 🦢 🦅 🦉 🦚 🦜 🦇 🐺 🐗 🐴 🦄 🐝 🐛 \n🦋 🐌 🐚 🐞 🐜 🦗 🕷 🕸 🦂 🦟 🦠 🐢 🐍 🦎 \n🦖 🦕 🐙 🦑 🦐 🦀 🐡 🐠 🐟 🐬 🐳 🐋 🦈 🐊 \n🐅 🐆 🦓 🦍 🐘 🦏 🦛 🐪 🐫 🦙 🦒 🐃 🐂 🐄 \n🐎 🐖 🐏 🐑 🐐 🦌 🐕 🐩 🐈 🐓 🦃 🕊 🐇 🐁 \n🐀 🐿 🦔 🐾 🐉 🐲 🌵 🎄 🌲 🌳 🌴 🌱 🌿 ☘️ \n🍀 🎍 🎋 🍃 🍂 🍁 🍄 🌾 💐 🌷 🌹 🥀 🌺 🌸 \n🌼 🌻 🌞 🌝 🌛 🌜 🌚 🌕 🌖 🌗 🌘 🌑 🌒 🌓 \n🌔 🌙 🌎 🌍 🌏 💫 ⭐️ 🌟 ✨ ⚡️ ☄️ 💥 🔥 🌪 \n🌈 ☀️ 🌤 ⛅️ 🌥 ☁️ 🌦 🌧 ⛈ 🌩 🌨 ❄️ ☃️ ⛄️ \n🌬 💨 💧 💦 ☔️ ☂️ 🌊 🌫',
97 | x: 603.5,
98 | y: 240,
99 | parent: 0,
100 | stroke: '#F2D3AC',
101 | component: 'node',
102 | editing: false,
103 | width: 367.5,
104 | height: 436,
105 | isRightSide: false,
106 | isUpSide: true,
107 | isHaveChildren: false
108 | }
109 | ],
110 | [
111 | '3f867e4a-3e4c-0ad7-3c97-cd5d6b84d03a',
112 | {
113 | id: '3f867e4a-3e4c-0ad7-3c97-cd5d6b84d03a',
114 | name: '## Food & Drink\n\n🍏 🍎 🍐 🍊 🍋 🍌 🍉 🍇 🍓 🍈 🍒 🍑 🍍 🥭 🥥 \n🥝 🍅 🍆 🥑 🥦 🥒 🥬 🌶 🌽 🥕 🥔 🍠 🥐 🍞 🥖 \n🥨 🥯 🧀 🥚 🍳 🥞 🥓 🥩 🍗 🍖 🌭 🍔 🍟 🍕 🥪 \n🥙 🌮 🌯 🥗 🥘 🥫 🍝 🍜 🍲 🍛 🍣 🍱 🥟 🍤 🍙 \n🍚 🍘 🍥 🥮 🥠 🍢 🍡 🍧 🍨 🍦 🥧 🍰 🎂 🍮 🍭 \n🍬 🍫 🍿 🧂 🍩 🍪 🌰 🥜 🍯 🥛 🍼 ☕️ 🍵 🥤 🍶 \n🍺 🍻 🥂 🍷 🥃 🍸 🍹 🍾 🥄 🍴 🍽 🥣 🥡 🥢\n',
115 | x: 960.5,
116 | y: 157,
117 | parent: 0,
118 | stroke: '#4A3CA6',
119 | component: 'node',
120 | editing: false,
121 | width: 401.5,
122 | height: 292.2109375,
123 | isRightSide: true,
124 | isUpSide: true,
125 | isHaveChildren: false
126 | }
127 | ],
128 | [
129 | 'ee59b644-f107-a12a-9640-4a7fbff8498b',
130 | {
131 | id: 'ee59b644-f107-a12a-9640-4a7fbff8498b',
132 | name: '## Activity and Sports\n\n⚽️ 🏀 🏈 ⚾️ 🥎 🏐 🏉 🎾 🥏 🎱 🏓 🏸 🥅 🏒 🏑 🥍 🏏 ⛳️ 🏹 🎣\n 🥊 🥋 🎽 ⛸ 🥌 🛷 🛹 🎿 ⛷ 🏂 🏋️\u200d♀️ 🏋🏻\u200d♀️ 🏋🏼\u200d♀️ 🏋🏽\u200d♀️ 🏋🏾\u200d♀️ 🏋🏿\u200d♀️ 🏋️\u200d♂️ 🏋🏻\u200d♂️ 🏋🏼\u200d♂️ 🏋🏽\u200d♂️ \n🏋🏾\u200d♂️ 🏋🏿\u200d♂️ 🤼\u200d♀️ 🤼\u200d♂️ 🤸\u200d♀️ 🤸🏻\u200d♀️ 🤸🏼\u200d♀️ 🤸🏽\u200d♀️ 🤸🏾\u200d♀️ 🤸🏿\u200d♀️ 🤸\u200d♂️ 🤸🏻\u200d♂️ 🤸🏼\u200d♂️ 🤸🏽\u200d♂️ 🤸🏾\u200d♂️ 🤸🏿\u200d♂️ ⛹️\u200d♀️ ⛹🏻\u200d♀️ ⛹🏼\u200d♀️ ⛹🏽\u200d♀️ \n⛹🏾\u200d♀️ ⛹🏿\u200d♀️ ⛹️\u200d♂️ ⛹🏻\u200d♂️ ⛹🏼\u200d♂️ ⛹🏽\u200d♂️ ⛹🏾\u200d♂️ ⛹🏿\u200d♂️ 🤺 🤾\u200d♀️ 🤾🏻\u200d♀️ 🤾🏼\u200d♀️ 🤾🏾\u200d♀️ 🤾🏾\u200d♀️ 🤾🏿\u200d♀️ 🤾\u200d♂️ 🤾🏻\u200d♂️ 🤾🏼\u200d♂️ 🤾🏽\u200d♂️ 🤾🏾\u200d♂️ \n🤾🏿\u200d♂️ 🏌️\u200d♀️ 🏌🏻\u200d♀️ 🏌🏼\u200d♀️ 🏌🏽\u200d♀️ 🏌🏾\u200d♀️ 🏌🏿\u200d♀️ 🏌️\u200d♂️ 🏌🏻\u200d♂️ 🏌🏼\u200d♂️ 🏌🏽\u200d♂️ 🏌🏾\u200d♂️ 🏌🏿\u200d♂️ 🏇 🏇🏻 🏇🏼 🏇🏽 🏇🏾 🏇🏿 🧘\u200d♀️ \n🧘🏻\u200d♀️ 🧘🏼\u200d♀️ 🧘🏽\u200d♀️ 🧘🏾\u200d♀️ 🧘🏿\u200d♀️ 🧘\u200d♂️ 🧘🏻\u200d♂️ 🧘🏼\u200d♂️ 🧘🏽\u200d♂️ 🧘🏾\u200d♂️ 🧘🏿\u200d♂️ 🏄\u200d♀️ 🏄🏻\u200d♀️ 🏄🏼\u200d♀️ 🏄🏽\u200d♀️ 🏄🏾\u200d♀️ 🏄🏿\u200d♀️ 🏄\u200d♂️ 🏄🏻\u200d♂️ 🏄🏼\u200d♂️ \n🏄🏽\u200d♂️ 🏄🏾\u200d♂️ 🏄🏿\u200d♂️ 🏊\u200d♀️ 🏊🏻\u200d♀️ 🏊🏼\u200d♀️ 🏊🏽\u200d♀️ 🏊🏾\u200d♀️ 🏊🏿\u200d♀️ 🏊\u200d♂️ 🏊🏻\u200d♂️ 🏊🏼\u200d♂️ 🏊🏽\u200d♂️ 🏊🏾\u200d♂️ 🏊🏿\u200d♂️ 🤽\u200d♀️ 🤽🏻\u200d♀️ 🤽🏼\u200d♀️ 🤽🏽\u200d♀️ 🤽🏾\u200d♀️ \n🤽🏿\u200d♀️ 🤽\u200d♂️ 🤽🏻\u200d♂️ 🤽🏼\u200d♂️ 🤽🏽\u200d♂️ 🤽🏾\u200d♂️ 🤽🏿\u200d♂️ 🚣\u200d♀️ 🚣🏻\u200d♀️ 🚣🏼\u200d♀️ 🚣🏽\u200d♀️ 🚣🏾\u200d♀️ 🚣🏿\u200d♀️ 🚣\u200d♂️ 🚣🏻\u200d♂️ 🚣🏼\u200d♂️ 🚣🏽\u200d♂️ 🚣🏾\u200d♂️ 🚣🏿\u200d♂️ 🧗\u200d♀️ \n🧗🏻\u200d♀️ 🧗🏼\u200d♀️ 🧗🏽\u200d♀️ 🧗🏾\u200d♀️ 🧗🏿\u200d♀️ 🧗\u200d♂️ 🧗🏻\u200d♂️ 🧗🏼\u200d♂️ 🧗🏽\u200d♂️ 🧗🏾\u200d♂️ 🧗🏿\u200d♂️ 🚵\u200d♀️ 🚵🏻\u200d♀️ 🚵🏼\u200d♀️ 🚵🏽\u200d♀️ 🚵🏾\u200d♀️ 🚵🏿\u200d♀️ 🚵\u200d♂️ 🚵🏻\u200d♂️ 🚵🏼\u200d♂️ \n🚵🏽\u200d♂️ 🚵🏾\u200d♂️ 🚵🏿\u200d♂️ 🚴\u200d♀️ 🚴🏻\u200d♀️ 🚴🏼\u200d♀️ 🚴🏽\u200d♀️ 🚴🏾\u200d♀️ 🚴🏿\u200d♀️ 🚴\u200d♂️ 🚴🏻\u200d♂️ 🚴🏼\u200d♂️ 🚴🏽\u200d♂️ 🚴🏾\u200d♂️ 🚴🏿\u200d♂️ 🏆 🥇 🥈 🥉 🏅 \n🎖 🏵 🎗 🎫 🎟 🎪 🤹\u200d♀️ 🤹🏻\u200d♀️ 🤹🏼\u200d♀️ 🤹🏽\u200d♀️ 🤹🏾\u200d♀️ 🤹🏿\u200d♀️ 🤹\u200d♂️ 🤹🏻\u200d♂️ 🤹🏼\u200d♂️ 🤹🏽\u200d♂️ 🤹🏾\u200d♂️ 🤹🏿\u200d♂️ 🎭 🎨 \n🎬 🎤 🎧 🎼 🎹 🥁 🎷 🎺 🎸 🎻 🎲 🧩 ♟ 🎯 🎳 🎮 🎰\n',
133 | x: 1369.5,
134 | y: 167,
135 | parent: 0,
136 | stroke: '#D93240',
137 | component: 'node',
138 | editing: false,
139 | width: 513.5,
140 | height: 417,
141 | isRightSide: true,
142 | isUpSide: true,
143 | isHaveChildren: false
144 | }
145 | ],
146 | [
147 | '00b1ec04-0964-1dae-0fef-81a424a8e57e',
148 | {
149 | id: '00b1ec04-0964-1dae-0fef-81a424a8e57e',
150 | name: '## Travel & Places\n\n🚗 🚕 🚙 🚌 🚎 🏎 🚓 🚑 🚒 🚐 🚚 🚛 🚜 🛴 🚲 🛵\n 🏍 🚨 🚔 🚍 🚘 🚖 🚡 🚠 🚟 🚃 🚋 🚞 🚝 🚄 🚅 🚈 \n🚂 🚆 🚇 🚊 🚉 ✈️ 🛫 🛬 🛩 💺 🛰 🚀 🛸 🚁 🛶 ⛵️ \n🚤 🛥 🛳 ⛴ 🚢 ⚓️ ⛽️ 🚧 🚦 🚥 🚏 🗺 🗿 🗽 🗼 🏰 \n🏯 🏟 🎡 🎢 🎠 ⛲️ ⛱ 🏖 🏝 🏜 🌋 ⛰ 🏔 🗻 🏕 ⛺️ \n🏠 🏡 🏘 🏚 🏗 🏭 🏢 🏬 🏣 🏤 🏥 🏦 🏨 🏪 🏫 🏩 \n💒 🏛 ⛪️ 🕌 🕍 🕋 ⛩ 🛤 🛣 🗾 🎑 🏞 🌅 🌄 🌠 🎇 \n🎆 🌇 🌆 🏙 🌃 🌌 🌉 🌁',
151 | x: 951.5,
152 | y: 1079,
153 | parent: 0,
154 | component: 'node',
155 | editing: false,
156 | width: 413.5,
157 | height: 293.75,
158 | isRightSide: true,
159 | isUpSide: false,
160 | isHaveChildren: false
161 | }
162 | ],
163 | [
164 | '1a09e419-20f2-e507-3798-ef8c8a3dbc4c',
165 | {
166 | id: '1a09e419-20f2-e507-3798-ef8c8a3dbc4c',
167 | name: '## Objects\n\n⌚️ 📱 📲 💻 ⌨️ 🖥 🖨 🖱 🖲 🕹 🗜 💽 💾 💿 📀 📼 📷 \n📸 📹 🎥 📽 🎞 📞 ☎️ 📟 📠 📺 📻 🎙 🎚 🎛 ⏱ ⏲ ⏰ \n🕰 ⌛️ ⏳ 📡 🔋 🔌 💡 🔦 🕯 🗑 🛢 💸 💵 💴 💶 💷 💰 \n💳 🧾 💎 ⚖️ 🔧 🔨 ⚒ 🛠 ⛏ 🔩 ⚙️ ⛓ 🔫 💣 🔪 🗡 ⚔️ \n🛡 🚬 ⚰️ ⚱️ 🏺 🧭 🧱 🔮 🧿 🧸 📿 💈 ⚗️ 🔭 🧰 🧲 🧪 \n🧫 🧬 🧯 🔬 🕳 💊 💉 🌡 🚽 🚰 🚿 🛁 🛀 🛀🏻 🛀🏼 🛀🏽 🛀🏾 \n🛀🏿 🧴 🧵 🧶 🧷 🧹 🧺 🧻 🧼 🧽 🛎 🔑 🗝 🚪 🛋 🛏 🛌 \n🖼 🛍 🧳 🛒 🎁 🎈 🎏 🎀 🎊 🎉 🧨 🎎 🏮 🎐 🧧 ✉️ 📩 \n📨 📧 💌 📥 📤 📦 🏷 📪 📫 📬 📭 📮 📯 📜 📃 📄 📑 \n📊 📈 📉 🗒 🗓 📆 📅 📇 🗃 🗳 🗄 📋 📁 📂 🗂 🗞 📰 \n📓 📔 📒 📕 📗 📘 📙 📚 📖 🔖 🔗 📎 🖇 📐 📏 📌 📍 \n✂️ 🖊 🖋 ✒️ 🖌 🖍 📝 ✏️ 🔍 🔎 🔏 🔐 🔒 🔓',
168 | x: 228.5,
169 | y: 416,
170 | parent: 0,
171 | stroke: '#B4B4B4',
172 | component: 'node',
173 | editing: false,
174 | width: 435.5,
175 | height: 575.140625,
176 | isRightSide: false,
177 | isUpSide: true,
178 | isHaveChildren: false
179 | }
180 | ],
181 | [
182 | '6577030a-ac89-75ef-6558-0d04706b282a',
183 | {
184 | id: '6577030a-ac89-75ef-6558-0d04706b282a',
185 | name: '## Symbols\n\n❤️ 🧡 💛 💚 💙 💜 🖤 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟\n ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ \n♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 \n🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 \n❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ \n❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ \n✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 \n🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 \n🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ⏏️ ▶️ ⏸ \n⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ \n↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ ♾ \n💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 🔜 ✔️ ☑️ 🔘 ⚪️ ⚫️ \n🔴 🔵 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ \n⬜️ 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁\u200d🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 \n🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 \n🕟 🕠 🕡 🕢 🕣 🕤 🕥 🕦 🕧',
186 | x: 200.5,
187 | y: 904,
188 | parent: 0,
189 | stroke: '#5F5F5F',
190 | component: 'node',
191 | editing: false,
192 | width: 446.5,
193 | height: 554.5,
194 | isRightSide: false,
195 | isUpSide: false,
196 | isHaveChildren: false
197 | }
198 | ],
199 | [
200 | 'e67b4faf-9cbc-309c-2009-c22553e126d0',
201 | {
202 | id: 'e67b4faf-9cbc-309c-2009-c22553e126d0',
203 | name: '## Flags\n🏳️ 🏴 🏁 🚩 🏳️\u200d🌈 🏴\u200d☠️ 🇦🇫 🇦🇽 🇦🇱 🇩🇿 🇦🇸 🇦🇩 🇦🇴 🇦🇮 🇦🇶\n 🇦🇬 🇦🇷 🇦🇲 🇦🇼 🇦🇺 🇦🇹 🇦🇿 🇧🇸 🇧🇭 🇧🇩 🇧🇧 🇧🇾 🇧🇪 🇧🇿 🇧🇯 🇧🇲 \n🇧🇹 🇧🇴 🇧🇦 🇧🇼 🇧🇷 🇮🇴 🇻🇬 🇧🇳 🇧🇬 🇧🇫 🇧🇮 🇰🇭 🇨🇲 🇨🇦 🇮🇨 🇨🇻 \n🇧🇶 🇰🇾 🇨🇫 🇹🇩 🇨🇱 🇨🇳 🇨🇽 🇨🇨 🇨🇴 🇰🇲 🇨🇬 🇨🇩 🇨🇰 🇨🇷 🇨🇮 🇭🇷 \n🇨🇺 🇨🇼 🇨🇾 🇨🇿 🇩🇰 🇩🇯 🇩🇲 🇩🇴 🇪🇨 🇪🇬 🇸🇻 🇬🇶 🇪🇷 🇪🇪 🇪🇹 🇪🇺 \n🇫🇰 🇫🇴 🇫🇯 🇫🇮 🇫🇷 🇬🇫 🇵🇫 🇹🇫 🇬🇦 🇬🇲 🇬🇪 🇩🇪 🇬🇭 🇬🇮 🇬🇷 🇬🇱 \n🇬🇩 🇬🇵 🇬🇺 🇬🇹 🇬🇬 🇬🇳 🇬🇼 🇬🇾 🇭🇹 🇭🇳 🇭🇰 🇭🇺 🇮🇸 🇮🇳 🇮🇩 🇮🇷 \n🇮🇶 🇮🇪 🇮🇲 🇮🇱 🇮🇹 🇯🇲 🇯🇵 🎌 🇯🇪 🇯🇴 🇰🇿 🇰🇪 🇰🇮 🇽🇰 🇰🇼 🇰🇬 \n🇱🇦 🇱🇻 🇱🇧 🇱🇸 🇱🇷 🇱🇾 🇱🇮 🇱🇹 🇱🇺 🇲🇴 🇲🇰 🇲🇬 🇲🇼 🇲🇾 🇲🇻 🇲🇱 \n🇲🇹 🇲🇭 🇲🇶 🇲🇷 🇲🇺 🇾🇹 🇲🇽 🇫🇲 🇲🇩 🇲🇨 🇲🇳 🇲🇪 🇲🇸 🇲🇦 🇲🇿 🇲🇲 \n🇳🇦 🇳🇷 🇳🇵 🇳🇱 🇳🇨 🇳🇿 🇳🇮 🇳🇪 🇳🇬 🇳🇺 🇳🇫 🇰🇵 🇲🇵 🇳🇴 🇴🇲 🇵🇰 \n🇵🇼 🇵🇸 🇵🇦 🇵🇬 🇵🇾 🇵🇪 🇵🇭 🇵🇳 🇵🇱 🇵🇹 🇵🇷 🇶🇦 🇷🇪 🇷🇴 🇷🇺 🇷🇼 \n🇼🇸 🇸🇲 🇸🇦 🇸🇳 🇷🇸 🇸🇨 🇸🇱 🇸🇬 🇸🇽 🇸🇰 🇸🇮 🇬🇸 🇸🇧 🇸🇴 🇿🇦 🇰🇷 \n🇸🇸 🇪🇸 🇱🇰 🇧🇱 🇸🇭 🇰🇳 🇱🇨 🇵🇲 🇻🇨 🇸🇩 🇸🇷 🇸🇿 🇸🇪 🇨🇭 🇸🇾 🇹🇼 \n🇹🇯 🇹🇿 🇹🇭 🇹🇱 🇹🇬 🇹🇰 🇹🇴 🇹🇹 🇹🇳 🇹🇷 🇹🇲 🇹🇨 🇹🇻 🇻🇮 🇺🇬 🇺🇦 \n🇦🇪 🇬🇧 🏴 🏴 🏴 🇺🇳 🇺🇸 🇺🇾 🇺🇿 🇻🇺 🇻🇦 🇻🇪 🇻🇳 🇼🇫 🇪🇭 🇾🇪 \n🇿🇲 🇿🇼',
204 | x: 1592.5,
205 | y: 597,
206 | parent: 0,
207 | stroke: '#075978',
208 | component: 'node',
209 | editing: false,
210 | width: 420.5,
211 | height: 579.9609375,
212 | isRightSide: true,
213 | isUpSide: true,
214 | isHaveChildren: false
215 | }
216 | ],
217 | [
218 | 'e712716c-1cb7-7e3f-a574-efd9a01566be',
219 | {
220 | id: 'e712716c-1cb7-7e3f-a574-efd9a01566be',
221 | name: '## New emojis\n\n🥱 🤏 🦾 🦿 🦻 🧏 🧏\u200d♂️ 🧏\u200d♀️ 🧍 🧍\u200d♂️ 🧍\u200d♀️ 🧎 🧎\u200d♂️\n 🧎\u200d♀️ 👨\u200d🦯 👩\u200d🦯 👨\u200d🦼 👩\u200d🦼 👨\u200d🦽 👩\u200d🦽 🦧 🦮 🐕\u200d🦺 🦥 🦦 🦨 \n🦩 🧄 🧅 🧇 🧆 🧈 🦪 🧃 🧉 🧊 🛕 🦽 🦼 \n🛺 🪂 🪐 🤿 🪀 🪁 🦺 🥻 🩱 🩲 🩳 🩰 🪕 \n🪔 🪓 🦯 🩸 🩹 🩺 🪑 🪒 🤎 🤍 🟠 🟡 🟢 \n🟣 🟤 🟥 🟧 🟨 🟩 🟦 🟪 🟫',
222 | x: 1597.5,
223 | y: 986,
224 | parent: 0,
225 | component: 'node',
226 | editing: false,
227 | width: 347.5,
228 | height: 388.0078125,
229 | isRightSide: true,
230 | isUpSide: false,
231 | isHaveChildren: false
232 | }
233 | ]
234 | ],
235 | date: '2020-05-01 21:41:43',
236 | modified: '2020-05-01 22:00:43',
237 | name: 'mind-maps-by-beagl-19'
238 | }
239 |
--------------------------------------------------------------------------------
/src/fe/src/map-templates/markdown.js:
--------------------------------------------------------------------------------
1 | export default {
2 | title: 'Markdown 😎💪🏻 {index}',
3 | description: 'Markdown syntaxis in action.',
4 | content: [
5 | [
6 | 0,
7 | {
8 | id: 0,
9 | name: 'Markdown 😎💪🏻 {index}',
10 | x: 1314,
11 | y: 653,
12 | component: 'root',
13 | editing: false,
14 | width: 174.0078125,
15 | height: -756,
16 | isHaveChildren: true
17 | }
18 | ],
19 | [
20 | '3e1f7684-107b-534e-4a5c-f383086c1964',
21 | {
22 | id: '3e1f7684-107b-534e-4a5c-f383086c1964',
23 | name: '## Rules',
24 | x: 1471,
25 | y: 412,
26 | parent: 0,
27 | stroke: '#075978',
28 | component: 'node',
29 | editing: false,
30 | width: 140,
31 | height: 32,
32 | isRightSide: true,
33 | isUpSide: true,
34 | isHaveChildren: true
35 | }
36 | ],
37 | [
38 | 'e2f2441d-b126-982f-dd46-a8f2bc60fa3b',
39 | {
40 | id: 'e2f2441d-b126-982f-dd46-a8f2bc60fa3b',
41 | name: 'Three or more...\n\n---\n\nHyphens',
42 | x: 1546,
43 | y: 124,
44 | parent: '3e1f7684-107b-534e-4a5c-f383086c1964',
45 | stroke: '#075978',
46 | component: 'node',
47 | editing: false,
48 | width: 140,
49 | height: 32,
50 | isRightSide: true,
51 | isUpSide: true,
52 | isHaveChildren: false
53 | }
54 | ],
55 | [
56 | '7de14635-34d3-f95e-6b47-57316bb89e2b',
57 | {
58 | id: '7de14635-34d3-f95e-6b47-57316bb89e2b',
59 | name: '***\n\nAsterisks',
60 | x: 1702,
61 | y: 149,
62 | parent: '3e1f7684-107b-534e-4a5c-f383086c1964',
63 | stroke: '#075978',
64 | editing: false,
65 | component: 'node',
66 | width: 140,
67 | height: 32,
68 | isRightSide: true,
69 | isUpSide: true,
70 | isHaveChildren: false
71 | }
72 | ],
73 | [
74 | 'ad2448c1-d100-7ef9-6672-8f6a405a1b5f',
75 | {
76 | id: 'ad2448c1-d100-7ef9-6672-8f6a405a1b5f',
77 | name: '___\n\nUnderscores',
78 | x: 1756,
79 | y: 280,
80 | parent: '3e1f7684-107b-534e-4a5c-f383086c1964',
81 | stroke: '#075978',
82 | editing: false,
83 | component: 'node',
84 | width: 140,
85 | height: 32,
86 | isRightSide: true,
87 | isUpSide: true,
88 | isHaveChildren: false
89 | }
90 | ],
91 | [
92 | 'dc2f8c2c-efbb-5513-4736-cde5539eb408',
93 | {
94 | id: 'dc2f8c2c-efbb-5513-4736-cde5539eb408',
95 | name: '## Lists',
96 | x: 1591,
97 | y: 489,
98 | parent: 0,
99 | component: 'node',
100 | editing: false,
101 | width: 140,
102 | height: 32,
103 | isRightSide: true,
104 | isUpSide: true,
105 | isHaveChildren: true
106 | }
107 | ],
108 | [
109 | '0eda7a08-db39-4fe1-634d-596b0a81fb6c',
110 | {
111 | id: '0eda7a08-db39-4fe1-634d-596b0a81fb6c',
112 | name: '1. First ordered list item\n2. Another item\n1. Actual numbers don\'t matter, just that it\'s a number\n4. And another item.',
113 | x: 1873,
114 | y: 355,
115 | parent: 'dc2f8c2c-efbb-5513-4736-cde5539eb408',
116 | component: 'node',
117 | editing: false,
118 | width: 309,
119 | height: 100.625,
120 | isRightSide: true,
121 | isUpSide: true,
122 | isHaveChildren: false
123 | }
124 | ],
125 | [
126 | '5d996d9e-992b-2db3-55c4-1d551a50bcf9',
127 | {
128 | id: '5d996d9e-992b-2db3-55c4-1d551a50bcf9',
129 | name: '* Unordered list can use asterisks\n- Or minuses\n+ Or pluses',
130 | x: 1866,
131 | y: 467,
132 | parent: 'dc2f8c2c-efbb-5513-4736-cde5539eb408',
133 | component: 'node',
134 | editing: false,
135 | width: 321,
136 | height: 170.7890625,
137 | isRightSide: true,
138 | isUpSide: true,
139 | isHaveChildren: false
140 | }
141 | ],
142 | [
143 | '43757f48-edee-195c-151b-2a2d3d640382',
144 | {
145 | id: '43757f48-edee-195c-151b-2a2d3d640382',
146 | name: '## Headers',
147 | x: 1559,
148 | y: 618,
149 | parent: 0,
150 | stroke: '#5F5F5F',
151 | component: 'node',
152 | editing: false,
153 | width: 140,
154 | height: 32,
155 | isRightSide: true,
156 | isUpSide: true,
157 | isHaveChildren: true
158 | }
159 | ],
160 | [
161 | 'c85c17e1-e358-d7ec-014d-d5eb9e388ff3',
162 | {
163 | id: 'c85c17e1-e358-d7ec-014d-d5eb9e388ff3',
164 | name: '# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6',
165 | x: 2193,
166 | y: 664,
167 | parent: '43757f48-edee-195c-151b-2a2d3d640382',
168 | stroke: '#5F5F5F',
169 | component: 'node',
170 | editing: false,
171 | width: 140,
172 | height: 32,
173 | isRightSide: true,
174 | isUpSide: false,
175 | isHaveChildren: false
176 | }
177 | ],
178 | [
179 | 'c6ebdee8-ce51-aeee-401a-ec3c1263a9e4',
180 | {
181 | id: 'c6ebdee8-ce51-aeee-401a-ec3c1263a9e4',
182 | name: 'Alternatively, for H1 and H2, an underline-ish style:\n\nAlt-H1\n======\n\nAlt-H2\n------',
183 | x: 1781,
184 | y: 763,
185 | parent: '43757f48-edee-195c-151b-2a2d3d640382',
186 | stroke: '#5F5F5F',
187 | component: 'node',
188 | editing: false,
189 | width: 140,
190 | height: 32,
191 | isRightSide: true,
192 | isUpSide: false,
193 | isHaveChildren: false
194 | }
195 | ],
196 | [
197 | 'fdf44a2c-dac8-8d3c-3669-b8bfaca9e9a8',
198 | {
199 | id: 'fdf44a2c-dac8-8d3c-3669-b8bfaca9e9a8',
200 | name: '## Emphasis',
201 | x: 1467,
202 | y: 781,
203 | parent: 0,
204 | stroke: '#B4B4B4',
205 | component: 'node',
206 | editing: false,
207 | width: 140,
208 | height: 32,
209 | isRightSide: true,
210 | isUpSide: false,
211 | isHaveChildren: true
212 | }
213 | ],
214 | [
215 | '3a1a5f42-0cd0-a854-33d6-fae1b22d24c8',
216 | {
217 | id: '3a1a5f42-0cd0-a854-33d6-fae1b22d24c8',
218 | name: 'Emphasis, aka italics, with *asterisks* or _underscores_.\nStrong emphasis, aka bold, with **asterisks** or __underscores__.',
219 | x: 1667,
220 | y: 924,
221 | parent: 'fdf44a2c-dac8-8d3c-3669-b8bfaca9e9a8',
222 | stroke: '#B4B4B4',
223 | component: 'node',
224 | editing: false,
225 | width: 497,
226 | height: 182.0859375,
227 | isRightSide: true,
228 | isUpSide: false,
229 | isHaveChildren: false
230 | }
231 | ],
232 | [
233 | 'cc310c7f-b83d-1814-bd52-ff97f8cebecb',
234 | {
235 | id: 'cc310c7f-b83d-1814-bd52-ff97f8cebecb',
236 | name: 'Combined emphasis with **asterisks and _underscores_**.\n\nStrikethrough uses two tildes. ~~Scratch this.~~',
237 | x: 1666,
238 | y: 992,
239 | parent: 'fdf44a2c-dac8-8d3c-3669-b8bfaca9e9a8',
240 | stroke: '#B4B4B4',
241 | editing: false,
242 | component: 'node',
243 | width: 140,
244 | height: 32,
245 | isRightSide: true,
246 | isUpSide: false,
247 | isHaveChildren: false
248 | }
249 | ],
250 | [
251 | 'd38424db-55dd-56ad-5e92-c94acb110868',
252 | {
253 | id: 'd38424db-55dd-56ad-5e92-c94acb110868',
254 | name: '## Links',
255 | x: 987,
256 | y: 899,
257 | parent: 0,
258 | stroke: '#E23E2B',
259 | component: 'node',
260 | editing: false,
261 | width: 140,
262 | height: 32,
263 | isRightSide: false,
264 | isUpSide: false,
265 | isHaveChildren: true
266 | }
267 | ],
268 | [
269 | 'fafa4ce8-3a89-601f-055b-28b117dc06f2',
270 | {
271 | id: 'fafa4ce8-3a89-601f-055b-28b117dc06f2',
272 | name: '[I\'m a reference-style link][Arbitrary case-insensitive reference text]\n\n[I\'m a relative reference to a repository file](../blob/master/LICENSE)\n\n[You can use numbers for reference-style link definitions][1]\n\nOr leave it empty and use the [link text itself].\n\nURLs and URLs in angle brackets will automatically get turned into links. \nhttp://www.beagl.in.\n\n[arbitrary case-insensitive reference text]: https://www.mozilla.org\n[1]: http://slashdot.org\n[link text itself]: mailto:eg@beagl.in',
273 | x: 840,
274 | y: 1073,
275 | parent: 'd38424db-55dd-56ad-5e92-c94acb110868',
276 | stroke: '#E23E2B',
277 | component: 'node',
278 | editing: false,
279 | width: 140,
280 | height: 32,
281 | isRightSide: false,
282 | isUpSide: false,
283 | isHaveChildren: false
284 | }
285 | ],
286 | [
287 | '40298c2a-9a6e-d43e-0be5-bde98db91eb9',
288 | {
289 | id: '40298c2a-9a6e-d43e-0be5-bde98db91eb9',
290 | name: '[I\'m an inline-style link](https://www.google.com)\n\n[I\'m an inline-style link with title](https://www.google.com "Google\'s Homepage")',
291 | x: 734,
292 | y: 919,
293 | parent: 'd38424db-55dd-56ad-5e92-c94acb110868',
294 | stroke: '#E23E2B',
295 | editing: false,
296 | component: 'node',
297 | width: 140,
298 | height: 32,
299 | isRightSide: false,
300 | isUpSide: false,
301 | isHaveChildren: false
302 | }
303 | ],
304 | [
305 | 'f741beb1-8d8a-16a0-6a03-a21bafcc73aa',
306 | {
307 | id: 'f741beb1-8d8a-16a0-6a03-a21bafcc73aa',
308 | name: '## Tables',
309 | x: 1005,
310 | y: 590,
311 | parent: 0,
312 | stroke: '#A65427',
313 | component: 'node',
314 | editing: false,
315 | width: 140,
316 | height: 32,
317 | isRightSide: false,
318 | isUpSide: true,
319 | isHaveChildren: true
320 | }
321 | ],
322 | [
323 | '111576be-01d1-0d00-53da-223de11fc5ae',
324 | {
325 | id: '111576be-01d1-0d00-53da-223de11fc5ae',
326 | name: 'There must be at least 3 dashes separating each header cell.\nThe outer pipes (|) are optional, and you don\'t need to make the \nraw Markdown line up prettily. You can also use inline Markdown.\n\nMarkdown | Less | Pretty\n--- | --- | ---\n*Still* | `renders` | **nicely**\n1 | 2 | 3',
327 | x: 920,
328 | y: 669,
329 | parent: 'f741beb1-8d8a-16a0-6a03-a21bafcc73aa',
330 | stroke: '#A65427',
331 | component: 'node',
332 | editing: false,
333 | width: 140,
334 | height: 32,
335 | isRightSide: false,
336 | isUpSide: false,
337 | isHaveChildren: false
338 | }
339 | ],
340 | [
341 | 'f80686a5-52d7-5303-68d7-69f309e3df3d',
342 | {
343 | id: 'f80686a5-52d7-5303-68d7-69f309e3df3d',
344 | name: 'Colons can be used to align columns.\n\n| Tables | Are | Cool |\n| ------------- |:-------------:| -----:|\n| col 3 is | right-aligned | $1600 |\n| col 2 is | centered | $12 |\n| zebra stripes | are neat | $1 |\n',
345 | x: 905,
346 | y: 416,
347 | parent: 'f741beb1-8d8a-16a0-6a03-a21bafcc73aa',
348 | stroke: '#A65427',
349 | editing: false,
350 | component: 'node',
351 | width: 432,
352 | height: 374.8984375,
353 | isRightSide: false,
354 | isUpSide: true,
355 | isHaveChildren: false
356 | }
357 | ],
358 | [
359 | 'ad6d5513-4e66-09c6-4c39-48c400fb69c2',
360 | {
361 | id: 'ad6d5513-4e66-09c6-4c39-48c400fb69c2',
362 | name: '## Images',
363 | x: 1128,
364 | y: 375,
365 | parent: 0,
366 | stroke: '#FFAA38',
367 | component: 'node',
368 | editing: false,
369 | width: 140,
370 | height: 32,
371 | isRightSide: false,
372 | isUpSide: true,
373 | isHaveChildren: true
374 | }
375 | ],
376 | [
377 | '74f47ffb-3cec-55ba-069b-1bd41aa13273',
378 | {
379 | id: '74f47ffb-3cec-55ba-069b-1bd41aa13273',
380 | name: '### Reference-style: \n![alt text][logo]\n\n[logo]: http://beagl.in/_nuxt/img/32e557f.svg "Logo Title Text 2"',
381 | x: 612,
382 | y: 253,
383 | parent: 'ad6d5513-4e66-09c6-4c39-48c400fb69c2',
384 | stroke: '#FFAA38',
385 | editing: false,
386 | component: 'node',
387 | width: 140,
388 | height: 32,
389 | isRightSide: false,
390 | isUpSide: true,
391 | isHaveChildren: false
392 | }
393 | ],
394 | [
395 | 'a3f88ec2-dcf1-6714-4755-88ddaf743f55',
396 | {
397 | id: 'a3f88ec2-dcf1-6714-4755-88ddaf743f55',
398 | name: '### Inline-style: \n',
399 | x: 662,
400 | y: 112,
401 | parent: 'ad6d5513-4e66-09c6-4c39-48c400fb69c2',
402 | stroke: '#FFAA38',
403 | component: 'node',
404 | editing: false,
405 | width: 140,
406 | height: 32,
407 | isRightSide: false,
408 | isUpSide: true,
409 | isHaveChildren: false
410 | }
411 | ],
412 | [
413 | '2ffa4d2e-1467-204d-d00e-e3381ea2a6a1',
414 | {
415 | id: '2ffa4d2e-1467-204d-d00e-e3381ea2a6a1',
416 | name: '## Blockquotes\n\n> Blockquotes are very handy in email to emulate reply text.\n> This line is part of the same quote.',
417 | x: 1228,
418 | y: 70,
419 | parent: 0,
420 | stroke: '#E8E525',
421 | component: 'node',
422 | editing: false,
423 | width: 140,
424 | height: 32,
425 | isRightSide: false,
426 | isUpSide: true,
427 | isHaveChildren: false
428 | }
429 | ],
430 | [
431 | '1562aba0-2960-a8ce-def7-a61f46f3cb38',
432 | {
433 | id: '1562aba0-2960-a8ce-def7-a61f46f3cb38',
434 | name: '## Code\n\nInline `code` has `back-ticks around` it.',
435 | x: 1278,
436 | y: 1015,
437 | parent: 0,
438 | stroke: '#69B500',
439 | component: 'node',
440 | editing: false,
441 | width: 140,
442 | height: 32,
443 | isRightSide: false,
444 | isUpSide: false,
445 | isHaveChildren: false
446 | }
447 | ]
448 | ],
449 | date: '2020-05-01 19:34:31',
450 | modified: '2020-05-01 20:13:55',
451 | name: 'blank-map-3'
452 | }
453 |
--------------------------------------------------------------------------------
/src/fe/src/mock.js:
--------------------------------------------------------------------------------
1 | window.mmbApp = window.mmbApp || {
2 | ajaxUrl: 'http://localhost/mm/wp-json/mmb/',
3 | pluginUrl: 'http://localhost/mm/wp-content/plugins/mind-maps/',
4 | nonce: '',
5 | adminEmail: 'eg@beagl.in',
6 | textDirection: 'ltr',
7 | backgroundColor: '#e9eaec',
8 | homeUrl: 'http://localhost/mm'
9 | }
10 |
11 | window.mmb = window.mmb || {
12 | notify: () => {}
13 | }
14 |
--------------------------------------------------------------------------------
/src/fe/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import Home from '../views/Home.vue'
4 | import Editor from '../views/Editor.vue'
5 |
6 | Vue.use(VueRouter)
7 |
8 | const routes = [
9 | {
10 | path: '/',
11 | name: 'Home',
12 | component: Home
13 | },
14 | {
15 | path: '/map/:id',
16 | name: 'Map',
17 | component: Editor
18 | }
19 | ]
20 |
21 | const router = new VueRouter({
22 | routes
23 | })
24 |
25 | export default router
26 |
--------------------------------------------------------------------------------
/src/fe/src/utils/api/map.js:
--------------------------------------------------------------------------------
1 | import { PREFIX } from './maps'
2 |
3 | /**
4 | * Get one map.
5 | *
6 | * @param {number} id Map id.
7 | *
8 | * @returns {Promise}
9 | */
10 | export function one (id) {
11 | return Promise.resolve({ data: JSON.parse(localStorage.getItem(PREFIX + id)) })
12 | }
13 |
14 | /**
15 | * Save map.
16 | *
17 | * @param {number} id Map id.
18 | * @param {object} map Map data.
19 | *
20 | * @returns {Promise}
21 | */
22 | export function save (id, map) {
23 | localStorage.setItem(PREFIX + id, JSON.stringify(map))
24 | return Promise.resolve({ data: one(id) })
25 | }
26 |
--------------------------------------------------------------------------------
/src/fe/src/utils/api/maps.js:
--------------------------------------------------------------------------------
1 | import guid from 'lguid'
2 | import { chain } from 'lodash'
3 |
4 | export const PREFIX = 'map-'
5 |
6 | /**
7 | * Add one more map.
8 | *
9 | * @param {object} data Map data.
10 | *
11 | * @returns {Promise}
12 | */
13 | export function add (data) {
14 | const id = guid()
15 | const newData = {
16 | id,
17 | ...data
18 | }
19 | localStorage.setItem(PREFIX + id, JSON.stringify(newData))
20 | return Promise.resolve({ data: newData })
21 | }
22 |
23 | /**
24 | * Get maps.
25 | *
26 | * @returns {Promise}
27 | */
28 | export function all () {
29 | const res = chain(Object.keys(localStorage))
30 | .filter(key => key.indexOf(PREFIX) === 0)
31 | .map(key => JSON.parse(localStorage.getItem(key)))
32 | .value()
33 | return Promise.resolve({ data: res })
34 | }
35 |
36 | /**
37 | * Delete Maps.
38 | *
39 | * @param {object} ids Maps id's.
40 | *
41 | * @returns {Promise}
42 | */
43 | export function delMaps (ids) {
44 | const res = chain(ids)
45 | .forEach(id => localStorage.removeItem(PREFIX + id))
46 | .value()
47 | return Promise.resolve({ data: res })
48 | }
49 |
--------------------------------------------------------------------------------
/src/fe/src/utils/clockIndex.js:
--------------------------------------------------------------------------------
1 | export const RIGHT_SIDE = 1
2 | export const LEFT_SIDE = -1
3 | export const UP_SIDE = 10
4 | export const DOWN_SIDE = -10
5 | export const HAVHE_CHILDREN = 100
6 | export const NO_CHILDREN = -100
7 |
8 | /**
9 | * Calculating clock index. This is to prevent use to much Switch cases or if's.
10 | *
11 | * 11 = Right side up.
12 | * 9 = Left side up.
13 | * -9 = Rigth side down.
14 | * -11 = Left side down.
15 | *
16 | * @param {Object} node Object with isRightSide and isUpSide.
17 | * @returns {Number} 11 || 9 || -9 || -11
18 | */
19 | export function clockIndex ({ isRightSide, isUpSide }) {
20 | const leftRight = isRightSide ? RIGHT_SIDE : LEFT_SIDE
21 | const upDown = isUpSide ? UP_SIDE : DOWN_SIDE
22 |
23 | return leftRight + upDown
24 | }
25 |
26 | /**
27 | * Calculating clock index with children. This is to prevent use to much Switch cases or if's.
28 | *
29 | * left | up | have children --- 11 = Right side up.
30 | * -1 + 10 + 100 = 109
31 | *
32 | * left | down | have children --- -9 = Rigth side down.
33 | * -1 + -10 + 100 = 89
34 | *
35 | * left | up | no children --- -11 = Left side down.
36 | * -1 + 10 + -100 = -91
37 | *
38 | * left | down | no children --- -11 = Left side down.
39 | * -1 + -10 + -100 = -111
40 | *
41 | * right | up | have children --- 9 = Left side up.
42 | * 1 + 10 + 100 = 111
43 | *
44 | * right | down | have children --- -11 = Left side down.
45 | * 1 + -10 + 100 = 91
46 | *
47 | * right | up | no children --- -9 = Rigth side down.
48 | * 1 + 10 + -100 = -89
49 | *
50 | * right | down | no children --- -9 = Rigth side down.
51 | * 1 + -10 + -100 = -109
52 | *
53 | * @param {Object} Node Node to count index.
54 | * @returns {Number} 11 || 9 || -9 || -11
55 | */
56 | export function clockIndexWithChildren ({ isRightSide, isUpSide, isHaveChildren, component }) {
57 | if (component === 'root') {
58 | return -9
59 | }
60 | const leftRight = isRightSide ? RIGHT_SIDE : LEFT_SIDE
61 | const upDown = isUpSide ? UP_SIDE : DOWN_SIDE
62 | const haveNo = isHaveChildren ? HAVHE_CHILDREN : NO_CHILDREN
63 | const clock = new Map([
64 | [109, 11],
65 | [89, -9],
66 | [-91, -11],
67 | [-111, -11],
68 | [111, 9],
69 | [91, -11],
70 | [-89, -9],
71 | [-109, -9]
72 | ])
73 | return clock.get(leftRight + upDown + haveNo)
74 | }
75 |
--------------------------------------------------------------------------------
/src/fe/src/utils/iif.js:
--------------------------------------------------------------------------------
1 | import { isFunction } from 'lodash'
2 |
3 | /**
4 | * Wrap anything (except function) to function.
5 | * @param candidate Function candidate.
6 | */
7 | function wrapToFunction (candidate) {
8 | if (isFunction(candidate)) {
9 | return candidate
10 | }
11 | return () => candidate
12 | }
13 |
14 | /**
15 | * Decide by condition which function we should run.
16 | *
17 | * @param condition Condition
18 | * @param fn1 Function or true result.
19 | * @param fn2 Function or false result.
20 | */
21 | export default function (condition, fn1, fn2) {
22 | return function (...args) {
23 | if (wrapToFunction(condition)(...args) === true) {
24 | return wrapToFunction(fn1)(...args)
25 | }
26 | return wrapToFunction(fn2)(...args)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/fe/src/utils/isWheelRight.js:
--------------------------------------------------------------------------------
1 | export default function (event) {
2 | if (event.wheelDeltaX === 0) {
3 | return 0
4 | }
5 | return event.wheelDeltaX < 0 ? 1 : -1
6 | }
7 |
--------------------------------------------------------------------------------
/src/fe/src/utils/isWheelUp.js:
--------------------------------------------------------------------------------
1 | export default function (event) {
2 | if (event.wheelDeltaY === 0) {
3 | return 0
4 | }
5 | return event.wheelDeltaY > 0 ? 1 : -1
6 | }
7 |
--------------------------------------------------------------------------------
/src/fe/src/utils/mapOf.js:
--------------------------------------------------------------------------------
1 | export default function (values) {
2 | return new Map(values)
3 | }
4 |
--------------------------------------------------------------------------------
/src/fe/src/utils/wrap.js:
--------------------------------------------------------------------------------
1 | export function isInner (str, start, end, wherewith) {
2 | const innerBefore = str.substr(start, wherewith.length)
3 | const innerAfter = str.substr(end - wherewith.length, wherewith.length)
4 | return innerBefore === wherewith && innerAfter === wherewith
5 | }
6 |
7 | export function isOuter (str, start, end, wherewith) {
8 | return isInner(str, start - wherewith.length, end + wherewith.length, wherewith)
9 | }
10 |
11 | function remove (str, start, end, wherewith) {
12 | return str.slice(0, start - wherewith.length) + str.slice(start, end) + str.slice(end + wherewith.length, str.length)
13 | }
14 |
15 | function add (str, start, end, wherewith) {
16 | return str.slice(0, start) + `${wherewith}${str.substr(start, end - start)}${wherewith}` + str.slice(end, str.length)
17 | }
18 |
19 | export function wrap (str, start, end, wherewith = '**') {
20 | const outerStart = start - wherewith.length
21 | const outerEnd = end + wherewith.length
22 |
23 | if (isInner(str, start, end, wherewith) === true) {
24 | return {
25 | str: remove(str, start + wherewith.length, end - wherewith.length, wherewith),
26 | start: start,
27 | end: end - wherewith.length - wherewith.length
28 | }
29 | }
30 |
31 | if (isInner(str, outerStart, outerEnd, wherewith) === true) {
32 | return {
33 | str: remove(str, start, end, wherewith),
34 | start: start - wherewith.length,
35 | end: end - wherewith.length
36 | }
37 | }
38 |
39 | return {
40 | str: add(str, start, end, wherewith),
41 | start: start + wherewith.length,
42 | end: end + wherewith.length
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/fe/src/utils/wrapRef.js:
--------------------------------------------------------------------------------
1 | import { isRef, ref } from '@vue/composition-api'
2 |
3 | export default function (el) {
4 | return isRef(el) ? el : ref(el)
5 | }
6 |
--------------------------------------------------------------------------------
/src/fe/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/fe/src/views/Editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 | {{ list.get(0).name }}
14 |
15 |
16 |
25 |
26 |
35 |
36 |
41 |
42 | JPEG
43 |
44 |
45 | ^⌥J
46 |
47 |
48 |
53 |
54 | PNG
55 |
56 |
57 | ^⌥P
58 |
59 |
60 |
61 |
66 |
67 | SVG
68 |
69 |
70 | ^⌥S
71 |
72 |
73 |
74 |
75 |
84 |
85 |
86 |
90 |
99 |
100 |
117 |
118 |
119 |
134 |
135 |
136 |
137 |
138 |
139 |
145 |
146 |
147 |
148 |
149 |
428 |
429 |
454 |
--------------------------------------------------------------------------------
/src/fe/src/views/ToolBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
18 |
67 |
68 |
116 |
--------------------------------------------------------------------------------
/src/fe/tests/e2e/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | 'cypress'
4 | ],
5 | env: {
6 | mocha: true,
7 | 'cypress/globals': true
8 | },
9 | rules: {
10 | strict: 'off'
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/fe/tests/e2e/plugins/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable arrow-body-style */
2 | // https://docs.cypress.io/guides/guides/plugins-guide.html
3 |
4 | // if you need a custom webpack configuration you can uncomment the following import
5 | // and then use the `file:preprocessor` event
6 | // as explained in the cypress docs
7 | // https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples
8 |
9 | // /* eslint-disable import/no-extraneous-dependencies, global-require */
10 | // const webpack = require('@cypress/webpack-preprocessor')
11 |
12 | module.exports = (on, config) => {
13 | // on('file:preprocessor', webpack({
14 | // webpackOptions: require('@vue/cli-service/webpack.config'),
15 | // watchOptions: {}
16 | // }))
17 |
18 | return Object.assign({}, config, {
19 | fixturesFolder: 'tests/e2e/fixtures',
20 | integrationFolder: 'tests/e2e/specs',
21 | screenshotsFolder: 'tests/e2e/screenshots',
22 | videosFolder: 'tests/e2e/videos',
23 | supportFile: 'tests/e2e/support/index.js'
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/src/fe/tests/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | // https://docs.cypress.io/api/introduction/api.html
2 |
3 | describe('My First Test', () => {
4 | it('Visits the app root url', () => {
5 | cy.visit('/')
6 | cy.contains('h1', 'Welcome to Your Vue.js App')
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/src/fe/tests/e2e/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This is will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/src/fe/tests/e2e/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/src/fe/tests/unit/example.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import HelloWorld from '@/components/HelloWorld.vue'
3 |
4 | describe('HelloWorld.vue', () => {
5 | it('renders props.msg when passed', () => {
6 | const msg = 'new message'
7 | const wrapper = shallowMount(HelloWorld, {
8 | propsData: { msg }
9 | })
10 | expect(wrapper.text()).toMatch(msg)
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/src/fe/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | chainWebpack: config => {
3 | if (config.plugins.has('extract-css')) {
4 | const extractCSSPlugin = config.plugin('extract-css')
5 | extractCSSPlugin && extractCSSPlugin.tap(() => [{
6 | filename: 'css/[name].css',
7 | chunkFilename: 'css/[name].css'
8 | }])
9 | }
10 | },
11 | configureWebpack: {
12 | output: {
13 | filename: 'js/[name].js',
14 | chunkFilename: 'js/[name].js',
15 | libraryExport: 'default'
16 | }
17 | },
18 | runtimeCompiler: true
19 | }
20 |
--------------------------------------------------------------------------------
/src/img/banner-1400x560.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/src/img/banner-1400x560.png
--------------------------------------------------------------------------------
/src/img/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/src/img/icon-128x128.png
--------------------------------------------------------------------------------
/src/img/icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theguriev/mind-maps-ext/b0905ec6c58ef9822364381d4f7bcf13a7904253/src/img/icon-48x48.png
--------------------------------------------------------------------------------
/src/img/logo_black.svg:
--------------------------------------------------------------------------------
1 |
79 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Mind maps",
3 | "description": "The clear way to share complex information. Mind maps is a collaborative tool that helps you make sense of complex things.",
4 | "version": "1.1.0",
5 | "manifest_version": 2,
6 | "icons": {
7 | "48": "img/icon-48x48.png",
8 | "128": "img/icon-128x128.png"
9 | },
10 | "browser_action": {
11 | "default_title": "Mind maps"
12 | },
13 | "background": {
14 | "scripts": [
15 | "background.js"
16 | ]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { CleanWebpackPlugin } = require('clean-webpack-plugin')
2 | const CopyPlugin = require('copy-webpack-plugin')
3 |
4 | module.exports = {
5 | mode: 'production',
6 | entry: './index.js',
7 | plugins: [
8 | new CleanWebpackPlugin(),
9 | new CopyPlugin([
10 | {
11 | from: 'src/fe/dist',
12 | to: 'release/'
13 | },
14 | {
15 | from: 'src/img',
16 | to: 'release/img'
17 | },
18 | {
19 | from: 'src/background.js',
20 | to: 'release/background.js'
21 | },
22 | {
23 | from: 'src/manifest.json',
24 | to: 'release/manifest.json'
25 | },
26 | ]),
27 | ],
28 | }
29 |
--------------------------------------------------------------------------------