neo.mjs 6.9.11 → 6.9.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/learnneo/index.html +4 -3
- package/apps/learnneo/neo-config.json +1 -4
- package/apps/learnneo/view/Viewport.mjs +11 -4
- package/apps/learnneo/view/ViewportController.mjs +2 -2
- package/apps/learnneo/view/home/ContentComponent.mjs +24 -0
- package/apps/learnneo/view/home/ContentTreeList.mjs +16 -11
- package/apps/learnneo/view/home/MainContainer.mjs +16 -16
- package/apps/learnneo/view/home/MainContainerModel.mjs +3 -5
- package/apps/newwebsite/index.html +3 -0
- package/buildScripts/convertDesignTokens.mjs +173 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/neo-config.json +2 -1
- package/package.json +2 -1
- package/resources/data/deck/learnneo/p/2023-10-08T20-20-37-336Z.md +17 -10
- package/resources/data/deck/learnneo/p/stylesheet.md +26 -8
- package/resources/data/deck/training/p/2023-01-10T02-21-54-303Z.md +1 -1
- package/resources/data/deck/training/t.json +1276 -1
- package/resources/design-tokens/json/component.json +288 -0
- package/resources/design-tokens/json/core.json +352 -0
- package/resources/design-tokens/json/semantic.json +231 -0
- package/resources/scss/src/apps/learnneo/Viewport.scss +3 -0
- package/resources/scss/src/apps/learnneo/home/ContentComponent.scss +61 -0
- package/resources/scss/src/apps/learnneo/home/ContentTreeList.scss +60 -13
- package/resources/scss/src/apps/learnneo/home/ContentView.scss +5 -2
- package/resources/scss/src/apps/newwebsite/MainContainer.css +33 -0
- package/resources/scss/src/apps/newwebsite/MainContainer.scss +14 -15
- package/resources/scss/src/list/Base.scss +1 -1
- package/resources/scss/theme-neo-light/Global.scss +33 -15
- package/resources/scss/theme-neo-light/design-tokens/Component.scss +62 -1
- package/resources/scss/theme-neo-light/design-tokens/Components.scss +3 -0
- package/resources/scss/theme-neo-light/design-tokens/Core.scss +65 -5
- package/resources/scss/theme-neo-light/design-tokens/Semantic.scss +61 -0
- package/resources/scss/theme-neo-light/list/Base.scss +29 -6
- package/src/DefaultConfig.mjs +2 -2
- package/src/controller/Base.mjs +31 -23
- package/src/data/connection/Xhr.mjs +1 -1
- package/src/form/field/Text.mjs +2 -2
package/apps/ServiceWorker.mjs
CHANGED
package/apps/learnneo/index.html
CHANGED
@@ -5,12 +5,13 @@
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
6
|
<meta charset="UTF-8">
|
7
7
|
<title>LearnNeo</title>
|
8
|
-
<link
|
9
|
-
|
8
|
+
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Source+Sans+3:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Source+Serif+4:ital,opsz,wght@0,8..60,400;0,8..60,500;0,8..60,600;0,8..60,700;1,8..60,400;1,8..60,500;1,8..60,600;1,8..60,700&display=swap" rel="stylesheet">
|
9
|
+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
10
|
+
rel="stylesheet">
|
10
11
|
</head>
|
11
12
|
|
12
13
|
<body>
|
13
14
|
<script src="../../src/MicroLoader.mjs" type="module"></script>
|
14
15
|
</body>
|
15
16
|
|
16
|
-
</html>
|
17
|
+
</html>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import BaseViewport
|
1
|
+
import BaseViewport from '../../../src/container/Viewport.mjs';
|
2
2
|
import ViewportController from './ViewportController.mjs';
|
3
3
|
|
4
4
|
/**
|
@@ -27,16 +27,23 @@ class Viewport extends BaseViewport {
|
|
27
27
|
*/
|
28
28
|
layout: {ntype: 'card'}
|
29
29
|
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
*
|
33
|
+
*/
|
30
34
|
onConstructed() {
|
31
35
|
super.onConstructed();
|
36
|
+
|
32
37
|
let me = this;
|
38
|
+
|
33
39
|
Neo.Main.getByPath({path: 'location.search'})
|
34
40
|
.then(data => {
|
35
41
|
const searchString = data?.substr(1) || '';
|
36
|
-
const search
|
37
|
-
me.deck
|
42
|
+
const search = searchString ? JSON.parse(`{"${decodeURI(searchString.replace(/&/g, "\",\"").replace(/=/g, "\":\""))}"}`) : {};
|
43
|
+
me.deck = search.deck || 'learnneo';
|
44
|
+
|
38
45
|
me.addCls(me.deck);
|
39
|
-
})
|
46
|
+
})
|
40
47
|
}
|
41
48
|
}
|
42
49
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import
|
1
|
+
import Controller from '../../../src/controller/Component.mjs';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* @class LearnNeo.view.ViewportController
|
5
5
|
* @extends Neo.controller.Component
|
6
6
|
*/
|
7
|
-
class ViewportController extends
|
7
|
+
class ViewportController extends Controller {
|
8
8
|
static config = {
|
9
9
|
/**
|
10
10
|
* @member {String} className='LearnNeo.view.ViewportController'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import Base from '../../../../src/component/Base.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class LearnNeo.view.home.ContentComponent
|
5
|
+
* @extends Neo.component.Base
|
6
|
+
*/
|
7
|
+
class ContentComponent extends Base {
|
8
|
+
static config = {
|
9
|
+
/**
|
10
|
+
* @member {String} className='LearnNeo.view.home.ContentComponent'
|
11
|
+
* @protected
|
12
|
+
*/
|
13
|
+
className: 'LearnNeo.view.home.ContentComponent',
|
14
|
+
/**
|
15
|
+
* @member {String[]} baseCls=['learn-content']
|
16
|
+
* @protected
|
17
|
+
*/
|
18
|
+
baseCls: ['learn-content']
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
Neo.applyClassConfig(ContentComponent);
|
23
|
+
|
24
|
+
export default ContentComponent;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import ContentStore from '../../store/Content.mjs'
|
2
|
-
import TreeList
|
2
|
+
import TreeList from '../../../../src/tree/List.mjs';
|
3
3
|
|
4
4
|
/**
|
5
5
|
* @class LearnNeo.view.home.ContentTreeList
|
@@ -16,6 +16,10 @@ class ContentTreeList extends TreeList {
|
|
16
16
|
* @member {String[]} cls=['topics-tree']
|
17
17
|
*/
|
18
18
|
cls: ['topics-tree'],
|
19
|
+
/**
|
20
|
+
* @member {Boolean} showCollapseExpandAllIcons=false
|
21
|
+
*/
|
22
|
+
showCollapseExpandAllIcons: false,
|
19
23
|
/**
|
20
24
|
* @member {Neo.data.Store} store=ContentStore
|
21
25
|
*/
|
@@ -23,7 +27,7 @@ class ContentTreeList extends TreeList {
|
|
23
27
|
}
|
24
28
|
|
25
29
|
get contentPath() {
|
26
|
-
return
|
30
|
+
return `../../resources/data/deck/${this.deck}`
|
27
31
|
}
|
28
32
|
|
29
33
|
/**
|
@@ -31,13 +35,13 @@ class ContentTreeList extends TreeList {
|
|
31
35
|
* @returns {Promise<void>}
|
32
36
|
*/
|
33
37
|
async doFetchContent(record) {
|
34
|
-
let me
|
38
|
+
let me = this,
|
35
39
|
path = `${me.contentPath}`;
|
36
40
|
|
37
41
|
path += record.path ? `/pages/${record.path}` : `/p/${record.id}.md`;
|
38
42
|
|
39
43
|
if (record.isLeaf && path) {
|
40
|
-
const data
|
44
|
+
const data = await fetch(path);
|
41
45
|
const content = await data.text();
|
42
46
|
|
43
47
|
await Neo.main.addon.Markdown.markdownToHtml(content)
|
@@ -46,9 +50,9 @@ class ContentTreeList extends TreeList {
|
|
46
50
|
component: me,
|
47
51
|
html,
|
48
52
|
record,
|
49
|
-
isLab: record.name?.startsWith('Lab:')
|
53
|
+
isLab : record.name?.startsWith('Lab:')
|
50
54
|
}),
|
51
|
-
() => me.fire('contentChange', {component: me}))
|
55
|
+
() => me.fire('contentChange', {component: me}))
|
52
56
|
}
|
53
57
|
}
|
54
58
|
|
@@ -63,7 +67,7 @@ class ContentTreeList extends TreeList {
|
|
63
67
|
// TODO: Tree lists should do this themselves when their store is loaded.
|
64
68
|
me.store.data = data.json.data;
|
65
69
|
me.createItems(null, me.getListItemsRoot(), 0);
|
66
|
-
me.update()
|
70
|
+
me.update()
|
67
71
|
})
|
68
72
|
}
|
69
73
|
|
@@ -78,11 +82,12 @@ class ContentTreeList extends TreeList {
|
|
78
82
|
Neo.Main.getByPath({path: 'location.search'})
|
79
83
|
.then(data => {
|
80
84
|
const searchString = data?.substr(1) || '';
|
81
|
-
const search
|
82
|
-
me.deck
|
85
|
+
const search = searchString ? JSON.parse(`{"${decodeURI(searchString.replace(/&/g, "\",\"").replace(/=/g, "\":\""))}"}`) : {};
|
86
|
+
me.deck = search.deck || 'learnneo';
|
87
|
+
|
83
88
|
me.doLoadStore();
|
84
89
|
console.log(search);
|
85
|
-
})
|
90
|
+
})
|
86
91
|
}
|
87
92
|
|
88
93
|
/**
|
@@ -90,7 +95,7 @@ class ContentTreeList extends TreeList {
|
|
90
95
|
*/
|
91
96
|
onLeafItemClick(record) {
|
92
97
|
super.onLeafItemClick(record);
|
93
|
-
this.doFetchContent(record)
|
98
|
+
this.doFetchContent(record)
|
94
99
|
}
|
95
100
|
}
|
96
101
|
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import Container
|
2
|
-
import ContentView
|
3
|
-
import ContentTreeList
|
1
|
+
import Container from '../../../../src/container/Base.mjs';
|
2
|
+
import ContentView from './ContentView.mjs';
|
3
|
+
import ContentTreeList from './ContentTreeList.mjs';
|
4
4
|
import MainContainerController from './MainContainerController.mjs';
|
5
|
-
import MainContainerModel
|
6
|
-
import Splitter
|
5
|
+
import MainContainerModel from './MainContainerModel.mjs';
|
6
|
+
import Splitter from '../../../../src/component/Splitter.mjs';
|
7
7
|
|
8
8
|
/**
|
9
9
|
* @class LearnNeo.view.home.MainContainer
|
@@ -20,31 +20,33 @@ class MainContainer extends Container {
|
|
20
20
|
* @member {Neo.controller.Component} controller=MainContainerController
|
21
21
|
*/
|
22
22
|
controller: MainContainerController,
|
23
|
+
|
24
|
+
cls: 'learnneo-maincontainer',
|
23
25
|
/**
|
24
26
|
* @member {Object[]} items
|
25
27
|
*/
|
26
28
|
items: [{
|
27
|
-
module: Container,
|
28
|
-
layout: 'fit',
|
29
|
+
module : Container,
|
30
|
+
layout : 'fit',
|
29
31
|
minWidth: 350,
|
30
|
-
width: 350,
|
31
|
-
|
32
|
+
width : 350,
|
33
|
+
cls : 'sidenav-container',
|
32
34
|
items: [{
|
33
|
-
module: ContentTreeList,
|
35
|
+
module : ContentTreeList,
|
34
36
|
reference: 'tree',
|
35
37
|
listeners: {
|
36
38
|
contentChange: 'onContentChange',
|
37
39
|
}
|
38
40
|
}]
|
39
41
|
}, {
|
40
|
-
module: Splitter,
|
42
|
+
module : Splitter,
|
41
43
|
resizeTarget: 'previous',
|
42
|
-
size:
|
44
|
+
size : 4
|
43
45
|
}, {
|
44
|
-
module: ContentView,
|
46
|
+
module : ContentView,
|
45
47
|
reference: 'content',
|
46
48
|
listeners: {
|
47
|
-
edit: 'onContentEdit',
|
49
|
+
edit : 'onContentEdit',
|
48
50
|
refresh: 'onContentRefresh'
|
49
51
|
}
|
50
52
|
}],
|
@@ -57,8 +59,6 @@ class MainContainer extends Container {
|
|
57
59
|
*/
|
58
60
|
model: MainContainerModel
|
59
61
|
}
|
60
|
-
|
61
|
-
|
62
62
|
}
|
63
63
|
|
64
64
|
Neo.applyClassConfig(MainContainer);
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import Component from '../../../../src/model/Component.mjs';
|
2
|
-
import
|
3
|
-
import Store from '../../../../src/data/Store.mjs';
|
2
|
+
import Store from '../../store/Content.mjs';
|
4
3
|
|
5
4
|
/**
|
6
5
|
* @class LearnNeo.view.home.MainContainerModel
|
@@ -22,9 +21,8 @@ class MainContainerModel extends Component {
|
|
22
21
|
*/
|
23
22
|
stores: {
|
24
23
|
tree: {
|
25
|
-
|
26
|
-
|
27
|
-
responseRoot: "data",
|
24
|
+
module : Store,
|
25
|
+
responseRoot: 'data'
|
28
26
|
}
|
29
27
|
}
|
30
28
|
}
|
@@ -4,6 +4,9 @@
|
|
4
4
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
5
5
|
<meta charset="UTF-8">
|
6
6
|
<title>Neo Website</title>
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Source+Sans+3:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Source+Serif+4:ital,opsz,wght@0,8..60,400;0,8..60,500;0,8..60,600;0,8..60,700;1,8..60,400;1,8..60,500;1,8..60,600;1,8..60,700&display=swap" rel="stylesheet">
|
7
10
|
<body>
|
8
11
|
<script src="../../src/MicroLoader.mjs" type="module"></script>
|
9
12
|
</body>
|
@@ -0,0 +1,173 @@
|
|
1
|
+
import fs from 'fs-extra';
|
2
|
+
import os from 'os';
|
3
|
+
import path from 'path';
|
4
|
+
|
5
|
+
let jsonPath = './resources/design-tokens/json',
|
6
|
+
jsonFolder = fs.readdirSync(jsonPath),
|
7
|
+
tokenPrefix = '',
|
8
|
+
tokenRegex = new RegExp(/{(.*?)}/g),
|
9
|
+
emptyString, fileContent, keyMaxLength, map, match, matches, output;
|
10
|
+
|
11
|
+
function capitalize(value) {
|
12
|
+
return value[0].toUpperCase() + value.slice(1);
|
13
|
+
}
|
14
|
+
|
15
|
+
function createEmptyString(len) {
|
16
|
+
return ' '.repeat(len);
|
17
|
+
}
|
18
|
+
|
19
|
+
function parseTokens(fileContent, prefix=tokenPrefix, map=[]) {
|
20
|
+
let baseKey, baseValue, keyValue, keys, modify, ns;
|
21
|
+
|
22
|
+
Object.entries(fileContent).forEach(([key, value]) => {
|
23
|
+
key = key.replace(/\?/g, '');
|
24
|
+
key = key.replace(/&/g, '-'); // some token names contain & chars
|
25
|
+
ns = prefix === tokenPrefix ? (tokenPrefix + key) : key === 'value' ? prefix : `${prefix}-${key}`;
|
26
|
+
|
27
|
+
if (typeof value === 'object') {
|
28
|
+
keys = Object.keys(value);
|
29
|
+
modify = value[keys[0]]?.$extensions?.['studio.tokens']?.modify || // the first key could contain the value,
|
30
|
+
value[keys[1]]?.$extensions?.['studio.tokens']?.modify; // so we are checking the 2nd too
|
31
|
+
|
32
|
+
if (modify) {
|
33
|
+
// assuming that each object contains its base value
|
34
|
+
keys.forEach(objKey => {
|
35
|
+
if (!value[objKey].$extensions) {
|
36
|
+
baseKey = objKey;
|
37
|
+
baseValue = value[baseKey].value;
|
38
|
+
}
|
39
|
+
});
|
40
|
+
|
41
|
+
keys.forEach(objKey => {
|
42
|
+
if (objKey !== baseKey) {
|
43
|
+
modify = value[objKey].$extensions?.['studio.tokens']?.modify;
|
44
|
+
keyValue = `${modify.type}(${baseValue}, ${modify.value * 100}%)`;
|
45
|
+
|
46
|
+
map.push([`${ns}-${objKey}`, keyValue]);
|
47
|
+
} else {
|
48
|
+
parseTokens(value[baseKey], `${ns}-${baseKey}`, map);
|
49
|
+
}
|
50
|
+
})
|
51
|
+
} else {
|
52
|
+
parseTokens(value, ns, map);
|
53
|
+
}
|
54
|
+
} else if (key !== 'description' && key !== 'type') {
|
55
|
+
if (typeof value === 'string') {
|
56
|
+
if (!value.includes('{')) {
|
57
|
+
if (value.includes(' ')) {
|
58
|
+
value = `'${value}'`;
|
59
|
+
}
|
60
|
+
} else {
|
61
|
+
value = value.replace(/\?/g, '');
|
62
|
+
matches = value.matchAll(tokenRegex);
|
63
|
+
|
64
|
+
// replace . with - only inside each token
|
65
|
+
for (match of matches) {
|
66
|
+
value = value.replace(match[0], match[0].replace(/\./g, '-'));
|
67
|
+
}
|
68
|
+
|
69
|
+
/*
|
70
|
+
* some design tokens contain operations without empty spaces
|
71
|
+
* e.g. {token}*0.9
|
72
|
+
* calc() relies on having spaces around operators
|
73
|
+
*/
|
74
|
+
value = value.replace(/(\S)(\*)(\S)/g, '$1 $2 $3');
|
75
|
+
value = value.replace(/(\S)(\/)(\S)/g, '$1 $2 $3');
|
76
|
+
|
77
|
+
// most likely a multiplication
|
78
|
+
if (!value.endsWith('}')) {
|
79
|
+
value = `calc(${value})`;
|
80
|
+
}
|
81
|
+
|
82
|
+
// convert tokens into CSS variables
|
83
|
+
value = value.replace(/{(.*?)}/g, `var(--${tokenPrefix}$1)`);
|
84
|
+
|
85
|
+
// multiple occurrences of a css variable need to get wrapped into calc()
|
86
|
+
if (value.indexOf('var') !== value.lastIndexOf('var')) {
|
87
|
+
value = `calc(${value})`;
|
88
|
+
}
|
89
|
+
|
90
|
+
// -token needs to get converted
|
91
|
+
if (value.startsWith('-')) {
|
92
|
+
value = `calc(${value.substring(1)} * -1)`
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
map.push([ns, value]);
|
98
|
+
}
|
99
|
+
});
|
100
|
+
|
101
|
+
return map;
|
102
|
+
}
|
103
|
+
|
104
|
+
function replaceObjectValue(obj) {
|
105
|
+
Object.entries(obj).forEach(([key, value]) => {
|
106
|
+
if (key === 'value') {
|
107
|
+
if (typeof value === 'object') {
|
108
|
+
Object.entries(value).forEach(([valKey, prop]) => {
|
109
|
+
// some token vars contain an empty string, which SCSS can not handle.
|
110
|
+
if (prop === '') {
|
111
|
+
prop = 'none';
|
112
|
+
}
|
113
|
+
|
114
|
+
obj[valKey] = {
|
115
|
+
type : obj.type,
|
116
|
+
value: prop
|
117
|
+
};
|
118
|
+
});
|
119
|
+
|
120
|
+
delete obj.type;
|
121
|
+
delete obj.value;
|
122
|
+
}
|
123
|
+
} else if (typeof value === 'object') {
|
124
|
+
replaceObjectValue(value);
|
125
|
+
}
|
126
|
+
});
|
127
|
+
}
|
128
|
+
|
129
|
+
function sortArray(a, b) {
|
130
|
+
const nameA = a[0].toUpperCase();
|
131
|
+
const nameB = b[0].toUpperCase();
|
132
|
+
if (nameA < nameB) {
|
133
|
+
return -1;
|
134
|
+
}
|
135
|
+
if (nameA > nameB) {
|
136
|
+
return 1;
|
137
|
+
}
|
138
|
+
|
139
|
+
return 0;
|
140
|
+
}
|
141
|
+
|
142
|
+
jsonFolder.forEach(fileName => {
|
143
|
+
if (fileName.endsWith(".json")) {
|
144
|
+
console.log('Parsing file:', fileName);
|
145
|
+
|
146
|
+
fileContent = JSON.parse(fs.readFileSync(path.join(jsonPath, fileName)));
|
147
|
+
keyMaxLength = 0;
|
148
|
+
output = [':root .neo-theme-neo-light {'];
|
149
|
+
|
150
|
+
replaceObjectValue(fileContent);
|
151
|
+
|
152
|
+
map = parseTokens(fileContent);
|
153
|
+
|
154
|
+
map.sort(sortArray);
|
155
|
+
|
156
|
+
map.forEach(item => {
|
157
|
+
keyMaxLength = Math.max(item[0].length, keyMaxLength);
|
158
|
+
});
|
159
|
+
|
160
|
+
map.forEach(item => {
|
161
|
+
emptyString = createEmptyString(keyMaxLength - item[0].length);
|
162
|
+
|
163
|
+
output.push(` --${item[0] + emptyString}: ${item[1]};`);
|
164
|
+
});
|
165
|
+
|
166
|
+
output.push('}');
|
167
|
+
output.push('');
|
168
|
+
|
169
|
+
fileName = capitalize(fileName.split('.').shift()) + '.scss'
|
170
|
+
|
171
|
+
fs.writeFileSync(path.join('./resources/scss/theme-neo-light/design-tokens/', fileName), output.join(os.EOL));
|
172
|
+
}
|
173
|
+
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "6.9.
|
3
|
+
"version": "6.9.12",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -16,6 +16,7 @@
|
|
16
16
|
"build-all-questions": "node ./buildScripts/buildAll.mjs -f",
|
17
17
|
"build-themes": "node ./buildScripts/buildThemes.mjs -f",
|
18
18
|
"build-threads": "node ./buildScripts/webpack/buildThreads.mjs -f",
|
19
|
+
"convert-design-tokens": "node ./buildScripts/convertDesignTokens.mjs",
|
19
20
|
"create-app": "node ./buildScripts/createApp.mjs",
|
20
21
|
"create-class": "node ./buildScripts/createClass.mjs",
|
21
22
|
"create-component": "node ./buildScripts/createComponent.mjs",
|
@@ -1,29 +1,36 @@
|
|
1
1
|
Neo.mjs uses standard modular JavaScript, so you're free to use other class
|
2
2
|
features, like private members.
|
3
|
-
<pre class="
|
3
|
+
<pre><code class="javascript">
|
4
4
|
class Human extends Mammal {
|
5
5
|
static config = {
|
6
6
|
className: 'Simple.example.Human',
|
7
|
-
name: 'J. Doe',
|
8
|
-
married: false
|
7
|
+
name : 'J. Doe',
|
8
|
+
married : false
|
9
9
|
}
|
10
|
+
|
10
11
|
static #privateStaticField = 'foo'
|
12
|
+
|
11
13
|
#privateInstanceField = 'bar'
|
12
|
-
|
14
|
+
|
15
|
+
#privateInstanceMethod() {
|
13
16
|
console.log(`Psst. Don't tell anyone, but ${this.#privateInstanceField} and ${Human.#privateStaticField}`);
|
14
17
|
}
|
15
|
-
|
18
|
+
|
19
|
+
speak(tellSecret) {
|
16
20
|
console.log(`Hello! My name is ${this.name}. I am ${this.married?'':'not'} married.`);
|
17
21
|
if (tellSecret) this.#privateInstanceMethod();
|
18
22
|
}
|
19
|
-
|
23
|
+
|
24
|
+
yodel() {
|
20
25
|
console.log('Yodelay hee hoo!');
|
21
|
-
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
Neo.applyClassConfig(Human);
|
22
30
|
|
23
31
|
const myPerson = Neo.create(Human, {
|
24
32
|
name: 'Herbert'
|
25
33
|
});
|
26
|
-
myPerson.speak(true);
|
27
34
|
|
28
|
-
|
29
|
-
</pre>
|
35
|
+
myPerson.speak(true);
|
36
|
+
</code></pre>
|
@@ -1,9 +1,6 @@
|
|
1
|
-
###Advice
|
2
|
-
|
3
|
-
Training content is different than self-study content.
|
4
|
-
|
5
1
|
<details>
|
6
|
-
<summary>Training material</summary>
|
2
|
+
<summary>Training material advice</summary>
|
3
|
+
Training content is different than self-study content.
|
7
4
|
Training material _augments_ the lecture. The audience should be focused on what the speaker is
|
8
5
|
saying; the slides support the lecture. An important concept in writing
|
9
6
|
training material is to avoid a _wall of words_, where there are lengthy
|
@@ -12,6 +9,7 @@ with a lot of text, your audience will be reading while you are lecturing,
|
|
12
9
|
and information is lost.
|
13
10
|
</details>
|
14
11
|
|
12
|
+
|
15
13
|
# This is an h1
|
16
14
|
## This is an h2
|
17
15
|
### This is an h3
|
@@ -19,13 +17,33 @@ and information is lost.
|
|
19
17
|
|
20
18
|
<br>
|
21
19
|
|
22
|
-
|
20
|
+
To show highlighted source code use
|
21
|
+
<pre>
|
22
|
+
<pre>
|
23
|
+
<code class="javascript">
|
24
|
+
// Source code goes here
|
25
|
+
</code>
|
26
|
+
</pre>
|
27
|
+
|
28
|
+
<pre>
|
29
|
+
<code class="javascript">
|
30
|
+
import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
|
31
|
+
|
32
|
+
class Mammal extends Base {
|
33
|
+
static config = {
|
34
|
+
className: 'Simple.example.Mammal'
|
35
|
+
}
|
36
|
+
}
|
37
|
+
</code>
|
38
|
+
</pre>
|
39
|
+
|
40
|
+
For short in-line statements of code use <code> or backticks.
|
23
41
|
|
24
|
-
|
42
|
+
When definining variables avoid `var` — use `let` or `const` instead.
|
25
43
|
|
26
44
|
<br>
|
27
45
|
|
28
|
-
|
46
|
+
For expandable bullet points and lab steps use a <details> tag
|
29
47
|
<pre>
|
30
48
|
<details>
|
31
49
|
<summary>This describes the item</summary>
|
@@ -5,6 +5,6 @@
|
|
5
5
|
meeting app will have its own frame rate.)
|
6
6
|
|
7
7
|
Run the the prod version of one of the demos, like
|
8
|
-
the <a href="https://neomjs.github.io/pages/node_modules/neo.mjs/dist/production/examples/component/coronaHelix/index.html" target="">COVID-19 Helix</a> example. Note the delta-updates per second information
|
8
|
+
the <a href="https://neomjs.github.io/pages/node_modules/neo.mjs/dist/production/examples/component/coronaHelix/index.html" target="_blank">COVID-19 Helix</a> example. Note the delta-updates per second information
|
9
9
|
at the upper right. You're seeing 10,000 or 20,000 delta updates per
|
10
10
|
second as you zoom in and out and pan.
|