mirror of
https://github.com/noodlapp/noodl.git
synced 2026-01-11 23:02:53 +01:00
Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
338
packages/noodl-editor/docs/interactive-lessons.md
Normal file
338
packages/noodl-editor/docs/interactive-lessons.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# Interactive tutorials HOWTO
|
||||
|
||||
## Keyboard shortcuts
|
||||
|
||||
- `Shift + Cmd + T`: Restart tutorial
|
||||
- `Shift + Cmd + R`: Reload lesson (and images). Doesn't restart tutorial
|
||||
- `Shift + Cmd + N`: Jump to next step even if conditions aren't correct
|
||||
|
||||
## Tutorial file format
|
||||
|
||||
A tutorial is written in a .html file.
|
||||
|
||||
A step can be one of the following:
|
||||
|
||||
1. A modal popup. Intended to be used as the first step to explain the tutorial, but can be used anywhere during the tutorial.
|
||||
|
||||
An item that shows up in the "tutorial bar" at the bottom:
|
||||
|
||||
2. An item can have conditions, in which case the popup only is shown when the user clicks the item
|
||||
3. An item without conditions will show the popup automatically
|
||||
|
||||
### Step with just a modal
|
||||
|
||||
A popup in middle of screen you have to dismiss to continue
|
||||
|
||||
```html
|
||||
<div data-template="popup">... any html ...</div>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<div data-template="popup">
|
||||
<img src="cool-gif.gif" />
|
||||
<h2>Welcome to this tutorial</h2>
|
||||
<p>You're going to learn some awesome stuff</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Step without conditions
|
||||
|
||||
It's recommended to use `<h2>` in the item
|
||||
|
||||
Format is as follows:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<div data-template="item">
|
||||
<header>...header text and stuff ...</header>
|
||||
<h2>Some text</h2>
|
||||
</div>
|
||||
<div data-template="popup">... popup content ...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<div>
|
||||
<div data-template="item">
|
||||
<header>Info</header>
|
||||
<h2>The node graph</h2>
|
||||
</div>
|
||||
<div data-template="popup">
|
||||
<img src="node-graph.gif" />
|
||||
<h2>The node graph</h2>
|
||||
<p>Some text</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Step with conditions
|
||||
|
||||
Format is same as above, with two additions. Conditions and a checkmark.
|
||||
It's recommended to use `<h3>` in the item.
|
||||
|
||||
```html
|
||||
<div data-conditions="[ list of conditions as json ]" }>
|
||||
<div data-template="item">
|
||||
<header>...header text and stuff ... <span class="lesson-checkmark"></span></header>
|
||||
<h3>Some text</h3>
|
||||
</div>
|
||||
<div data-template="popup">... popup content ...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-conditions='[
|
||||
{"path":"/App:%Group:0","exists":true}
|
||||
]'
|
||||
>
|
||||
<div data-template="item">
|
||||
<header>Task <span class="lesson-checkmark"></span></header>
|
||||
<h3>Drag the text node back to make it visible again</h3>
|
||||
</div>
|
||||
|
||||
<div data-template="popup">
|
||||
<img src="drag-text-out.gif" />
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Step width
|
||||
|
||||
A step can have a custom width. Useful if the text doesnät fit the standard size:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<div data-template="item" style="width: 300px">...</div>
|
||||
<div data-template="popup">...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Conditions
|
||||
|
||||
A step can have conditions that are required to evaluate to true before the user can proceed to the next step.
|
||||
|
||||
### Paths
|
||||
|
||||
All conditions point to one or more node.
|
||||
The path to a node is specified by using a path that starts with the component name, and then any of the following tokens:
|
||||
|
||||
- `#label`: Look for a node with a label that matches the specified label
|
||||
- `%type`: Look for a node of a specific type
|
||||
- `2`: Look for a child index (in this case child 2, the third child)
|
||||
|
||||
The first part of a path is always a component.
|
||||
Second part looks for a root node that matches the token.
|
||||
Third part will look for a child in the matched root node.
|
||||
... and so on.
|
||||
|
||||
Example:
|
||||
|
||||
- `/Main:%Group`: "/Main" component -> Any root node with the type "Group". If there's more than one Group root node then the condition will just pick the first one it finds.
|
||||
- `/Main:%Group:%Button`: "/Main" component -> Any root node with the type "Group" -> First child that with the type "Button".
|
||||
- `/Main:#Some Label`: "/Main" component -> A root node with the label "Some Label"
|
||||
- `/Main:#Some Label:0`: "/Main" component -> A root node with the label "Some Label -> First child
|
||||
- `/Main:#Some Label:%Button`: "/Main" component -> A root node with the label "Some Label -> First child with the type "Button"
|
||||
- `/#Sheet A/Comp A:JavaScriptFunction`: Sheet "Sheet A" component "Comp A" -> A root node with the type "Function" (check project.json for the node types if unsure)
|
||||
|
||||
### Check if a node exist or not at the specified path:
|
||||
|
||||
Check if there's a node at the specified path
|
||||
|
||||
```json
|
||||
{"path":"/App:#root:1", "exists":true}]
|
||||
```
|
||||
|
||||
Or the inverse, that there's no node at that path
|
||||
|
||||
```json
|
||||
{"path":"/App:#root:1", "exists":false}]
|
||||
```
|
||||
|
||||
### Check for connection
|
||||
|
||||
Check if there's a connection between two nodes between the specified ports.
|
||||
|
||||
```json
|
||||
{
|
||||
"from": "/App:#nodeLabelA",
|
||||
"to": "/App:#nodeLabelB",
|
||||
"hasconnection": "sourcePortName,targetPortName"
|
||||
}
|
||||
```
|
||||
|
||||
### Check if a node has a specific label
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:#root:1",
|
||||
"haslabel": "Some label"
|
||||
}
|
||||
```
|
||||
|
||||
### Check if a node has a specific type
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:#root:1",
|
||||
"hastype": "Group"
|
||||
}
|
||||
```
|
||||
|
||||
### Check if paramters are set on a node
|
||||
|
||||
Check if a node has any value set on one or more paramters.
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:#root:1",
|
||||
"hasparams": "marginLeft,marginRight"
|
||||
}
|
||||
```
|
||||
|
||||
### Check parameters on a node
|
||||
|
||||
Check the value of one or more paramters. The values are the ones specified in the `project.json` file, so take a look there if unsure.
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:#root:1",
|
||||
"paramseq": {
|
||||
"color": "#000000",
|
||||
"width": { "value": 300, "unit": "px" },
|
||||
"alignX": "center",
|
||||
"alignY": "center",
|
||||
"sizeMode": "contentSize"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Example: Check for states in a state node
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:#root:1",
|
||||
"paramseq": {
|
||||
"paramseq": {
|
||||
"states": "Visible,Hidden",
|
||||
"values": "Opacity"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Check if a port exists on a node
|
||||
|
||||
Check if a node has a certain port.
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:#some function node",
|
||||
"hasport": "myInput"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Actions from buttons
|
||||
|
||||
### Exiting a lesson from a click event
|
||||
|
||||
A `data-click` attribute can be added on an HTML tag to make it trigger certain actions in the editor.
|
||||
|
||||
### Exiting a lesson
|
||||
|
||||
```html
|
||||
<button style="width: 150px" data-click="exitEditor">EXIT LESSON</button>
|
||||
```
|
||||
|
||||
## Examples of common nodes with non-obvious names
|
||||
|
||||
### Check if an Object node has certain properties.
|
||||
|
||||
NOTE: the order the properties are created matters, so they should be done step by step instead of all at once
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/My component:%Model2",
|
||||
"paramseq": {
|
||||
"properties": "url,author"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Check connection from Object node
|
||||
|
||||
```json
|
||||
{
|
||||
"from": "/My component:%Model2",
|
||||
"to": "/My component::%Image",
|
||||
"hasconnection": "prop-url,src"
|
||||
}
|
||||
```
|
||||
|
||||
### Check if a Page Router has certain pages
|
||||
|
||||
NOTE: the order the pages does <b>NOT</b> matters, so adding multiple pages in one step is fine.
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:%Group:%Router",
|
||||
"paramseq": {
|
||||
"pages": {
|
||||
"routes": ["/Page 1", "/Page 2", "/Page 3"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Check if a Page Router has a specific start page
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:%Group:%Router",
|
||||
"paramseq": {
|
||||
"pages": {
|
||||
"startPage": "/Page 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Check if a Navigate node points to a specific target page
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/App:%RouterNavigate",
|
||||
"paramseq": {
|
||||
"target": "/Page 2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Check a Page Input for a specific input and if it's connected
|
||||
|
||||
NOTE: if there's more than one page paramter, then it behaves like an Object. It's a comma separated list, and the order is important.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"path": "/Page 1:%PageInputs",
|
||||
"paramseq": {
|
||||
"pathParams": "myPageInput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": "/Page 1:%PageInputs",
|
||||
"to": "/Page 1:%Page:%Text",
|
||||
"hasconnection": "pm-myPageInput,text"
|
||||
}
|
||||
]
|
||||
```
|
||||
75
packages/noodl-editor/docs/sidebar.md
Normal file
75
packages/noodl-editor/docs/sidebar.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Create a Sidebar HOWTO
|
||||
|
||||
## Creating a sidebar
|
||||
|
||||
```tsx
|
||||
import React, { useState } from 'react';
|
||||
import { ReactView } from '../../../../shared/ReactView';
|
||||
|
||||
import { UndoQueue } from '@noodl-models/undo-queue-model';
|
||||
|
||||
import { PrimaryButton } from '@noodl-core-ui/inputs/PrimaryButton';
|
||||
import { Container, ContainerDirection } from '@noodl-core-ui/layout/Container';
|
||||
|
||||
function UndoQueuePanel({}) {
|
||||
const [queue, setQueue] = useState([]);
|
||||
|
||||
function refresh() {
|
||||
const undoQueue: TSFixme[] = UndoQueue.instance.queue;
|
||||
setQueue([...undoQueue]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container hasXSpacing hasYSpacing>
|
||||
<PrimaryButton label="Refresh" onClick={refresh} isGrowing />
|
||||
</Container>
|
||||
<Container hasXSpacing hasYSpacing direction={ContainerDirection.Vertical}>
|
||||
{queue.map((item, index) => (
|
||||
<PrimaryButton key={index} label={item.label} isGrowing />
|
||||
))}
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// NOTE: Once Frames component is rewritten to React we don't need to have the
|
||||
// ReactView here.
|
||||
export class UndoQueuePanelView extends ReactView<{}> {
|
||||
constructor(args) {
|
||||
super({});
|
||||
}
|
||||
|
||||
protected renderReact(props: {}): JSX.Element {
|
||||
return UndoQueuePanel({});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Register the Sidebar
|
||||
|
||||
```ts
|
||||
SidebarModel.instance.register({
|
||||
hidden: false,
|
||||
id: 'undo-queue',
|
||||
name: 'Undo Queue',
|
||||
order: 10,
|
||||
icon: 'sidebar-toolbar-components-icon',
|
||||
panel: (args) => new UndoQueuePanelView()
|
||||
});
|
||||
```
|
||||
|
||||
## Special Sidebar for a Node
|
||||
|
||||
Define the sidebar panel you want the node to have in the node definition.
|
||||
This will open that sidebar panel when the node is selected.
|
||||
|
||||
```ts
|
||||
{
|
||||
panels: [
|
||||
{
|
||||
name: "PortEditor",
|
||||
}
|
||||
],
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user