-
Notifications
You must be signed in to change notification settings - Fork 8
Creating Widgets
Widgets are multi-purpose independent windows. They can be used during tutorials to open up other media types (images, videos, gifs, audio, texts, 3D objects, etc). Widgets can also be there own miscellaneous utilities. For example we could create a widget that explains some concept using interactive graphics. Widgets can also be GUIs that interact with the netitor, for example a CSS generator that outputs to the line where the user's cursor is currently positioned. The sky's the limit!
The Widget class can be used to instantiate new widgets. A widget is a window styled to match netnet's current theme. This includes shadows that respond to the mouse's position. If the window manager update's netnet's theme all widgets will automatically update their themes to match. (for more info on NNW.updateTheme()
and other window manager methods refer to the nnw section in the Project Architecture wiki page)
To instantiate a new widget:
const w = new Widget({
title: 'settings',
innerHTML: element
})
Where the value of the innerHTML property can either be an string (including an html string like <h1>Hello World!</h1>
) or an instance of HTMLElement (ie. a DOM element, const element = document.createElement('h1')
). If we'd like to instantiate the widget at a particular location and/or at a particular size we can use these optional properties:
const w = new Widget({
title: 'settings', // required
innerHTML: element, // optional
x: 20, // optional
y: 20, // optional
z: 100, // optional
width: 500, // optional
height: 500 // optional
})
We can pass these properties a number or a CSS string, like x: '50vw'
and width: '100%'
and y: '100px'
.
All the properties passed in the constructor's options argument can also be accessed/updated via the instance's properties, for example:
w.title = 'layout settings'
w.innerHTML = '<h1>these are the options</h1>'
w.x = innerWidth / 2
w.y = '50vh'
w.z = 101
w.width = '100%'
w.height = '1080px'
It's important to note that instantiating the widget creates it in memory, but it does not visually present it to the user. In order to display the widget we need to use the instance's .open()
method. There's also the .close()
method for hiding the widget (while maintaining it in memory) as well as methods for resizing and positioning:
w.position(x, y, z) // update position
w.resize(width, height) // update size
w.open() // display
w.close() // hide
That said, if you want the StateManager to keep track of the Widget instance you should call STORE.dispatch('LOAD_WIDGETS', { name: w })
assuming w
is an instance of the Widget
class and 'name' is a unique key to be stored in the global WIDGETS
object. This has the added benefit of ensuring the widget shows up in the main menu's widgets sub-menu. For more info see the State Management Wiki
The basic widget class is great for doing things like loading up images or videos, but for more interesting/complicated widgets we can create our own widget classes by extending the base widget class, for example:
class RandomColor extends Widget {
constructor (opts) {
super(opts)
this.alpha = opts.alpha || false
this.title = 'Random Color'
this.innerHTML = `<button>insert color</button>`
this.$('button').onclick = () => { this.click() }
}
click () {
const r = Math.floor(Math.random() * 255)
const g = Math.floor(Math.random() * 255)
const b = Math.floor(Math.random() * 255)
const a = (this.alpha) ? Math.round(Math.random() * 10) / 10 : 1
const code = `rgba(${r}, ${g}, ${b}, ${a})`
NNE.cm.replaceSelection(code)
}
exampleMethod () {
/* another example */
}
}
const rc = new RandomColor({ x: 100, y: 20, alpha: true })
rc.open()
rc.exampleMethod()
The window manager handles loading all of netnet's widget classes when the page loads. In order for the window manager to find the widgets they need be saved in the www/widgets
directory. The directory also has an ExampleWidget.js
file which can be copied and used as a template or starting point.