This package represents a sample plugin for the DFOhub application.
It shows how to create a menu with a couple of pages and the corresponding routes.
In this sample package, there is just one file src/index.js containing the definition of the plugin. The real plugins will probably have a more structured organization of files.
Storybook is already included in the package, even if not used in this sample.
In this tutorial we will create the sample-plugin from scratch.
A plugin is simply an object with a name and an init method.
The init method is called with a function addElement as argument, which allows adding placeholders. So, the following is a simple definition of a plugin:
// file src/index.js inside this package
const pluginDefinition = {
name: 'sample-plugin',
init: ({ addElement }) => {
console.log('Hello!')
},
}
export default pluginDefinitionWe are exporting the plugin from our sample package, whose name id @dfohub/sample-plugin.
To install this plugin in your app, just pass it to the PluginsContextProvider imported from '@dfohub/core' inside your app, as follows:
// file src/App.js inside the 'app' package
import React from 'react'
import { PluginsContextProvider } from '@dfohub/core'
import samplePlugin from '@dfohub/sample-plugin'
function App() {
return (
<PluginsContextProvider plugins={[samplePlugin]}>
<div>Hello!</div>
</PluginsContextProvider>
)
}
export default AppThe actual App.js file inside the app package is more complex, but the code above is enough to install the plugin in the app.
Now, let's make our plugin do something more interesting, like creating a menu.
We can use the addElement function to create any kind of element.
For example, to create a menu item, we can write:
// file src/index.js inside this package
const initPlugin = ({ addElement }) => {
addElement('menu', {
name: 'home',
label: 'Home',
link: '/',
index: 10,
})
addElement('menu', {
name: 'about',
label: 'About',
link: '/about',
index: 20,
})
}
const pluginDefinition = {
name: 'sample-plugin',
init: initPlugin,
}
export default pluginDefinitionThis way, we have created two menu items. The addElement requires two parameters:
- the name of a group of elements (
menuin our code) - an object of any kind that is useful for our purpose
Note: the only constraint of the object is to have a property called index, that's used by the plugin system to return the elements in an indexed order.
To retrieve the menu items and display the whole menu, in our application, we can write:
import React from 'react'
import { Link } from 'react-router-dom'
import { usePlaceholder } from '@dfohub/core'
function Menu(props) {
const menu = usePlaceholder('menu')
return (
<div>
{menu.map(({ label, link, name }) => (
<Link
key={`${link}-${label}`}
to={link}>
{label}
</Link>
))}
</div>
)
}
export default MenuAs you can see, to get the menu items you can simply call the usePlaceholder hook from the core package.
Important: the component which calls the usePlaceholder hook must be hierarcally inside the PluginsContextProvider component.
The above code is extracted by the Menu component in the app package.
Have a look at its source code for the complete version.
Now, let's create the routes of the application.
We can add other calls to the addElement function in our plugin initialization, as follows:
addElement('router', {
index: 10,
path: '/',
Component: TestPage,
exact: true,
requireConnection: false,
templateProps: {
selected: 'home',
showMenu: true,
},
})
addElement('router', {
index: 20,
path: '/about',
Component: TestPage2,
exact: true,
requireConnection: true,
templateProps: {
selected: 'about',
showMenu: true,
},
})The name of the group of routes is router.
The object has all the information for its use inside the application (see src/router.js file in the app package):
indexfor sorting, as seen beforepath,Componentandexactare used by theRoutecomponentrequireConnectionis used to say that the route requires a connection to Ethereum, otherwise theConnectcomponent will be showntemplatePropscontains the props to pass to theMainTemplatecomponent:selectedcontains the menu item name which should be selected as current pageshowMenudefines if the menu should be shown for this Component
Storybook is integrated in this package even if the sample pages don't use it.
You can build Storybook with:
npm run build-storybookYou can launch Storybook with:
npm run storybookThis package uses rollup to create the bundle.
To build the package, you can use the lerna scripts in the root project (build and build-dev), as stated in the root project documentation.
If you prefer to build only this package, just run:
npm run buildto simply build the package, or
npm run build:devto build and keep watching for changes.