In case you haven't heard yet, Emdash is a successor to Wordpress written entirely in JavaScript using the Astro framework. I won't be going into detail about the features of Emdash. Instead I will be showing you how to create a pie chart widget for the dashboard.
1. Create a new Emdash project.
bun create emdash@latest
Walk through the setup process. I chose to use Cloudflare workers and the blog template.
Once the project is done installing, open up the project in your favorite editor. Then run the following to start the Astro server:
bun run dev
You may see some errors if you are on an early release of Emdash. You can ignore those errors. Somewhere in the output you will see a link to the Emdash site. It should be http://localhost:4321
2. Navigate through the setup process
You should see a button that says "Create a post." Click that to start the setup process. You will be prompted to fill out a name for the site and an email to associate with the passkey.
Once you run though the setup process you will see a screen welcoming you to emdash.
If you navigate to the plugins page you will see there are some plugins pre-installed. Eventually your custom plugin will show up on that page.
3. Initialize the plugin directory
Make a directory called plugins/hello-chart-plugin and open that directory in a new terminal. From there initialize a new bun project:
bun init -y
Next add the following to the package.json:
"name": "hello-chart-plugin",
"files": [
"src"
],
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"./sandbox": {
"types": "./dist/sandbox-entry.d.mts",
"default": "./dist/sandbox-entry.mjs"
}
},
"scripts": {
"build": "tsdown",
"dev": "tsdown --watch"
}
you will need to install a few dependencies for this plugin to work:
bun add emdash --peer
bun add -D tsdown @emdash-cms/blocks
Finally create a tsdown.config.ts file in the root of the plugin folder. Add the following config:
import { defineConfig } from "tsdown";
export default defineConfig({
entry: ["src/index.ts", "src/sandbox-entry.ts"],
format: ["esm"],
dts: true,
clean: true,
deps: {
neverBundle: ["emdash"],
},
});
4. Link the plugin package
Add the following to the package.json in the main emdash project directory.
"workspaces": [
"plugins/*"
],
"dependencies": {
...
"hello-chart-plugin": "workspace:*"
},
Next finish linking the plugin by running:
bun install
5. Create Plugin Entry Points
The first file you need for your plugin is src/index.ts. This file will be used by Vite to define your plugin.
import { type PluginDescriptor } from "emdash";
export function helloChartPlugin(): PluginDescriptor {
return {
id: "com.lucent.hello-chart-plugin",
version: "0.0.1",
format: "standard",
entrypoint: "hello-chart-plugin/sandbox",
adminWidgets: [{ id: "hello-chart", title: "Hello Chart", size: "half" }],
};
}
The id needs to be a unique id for your plugin. The entrypoint needs to match your plugin's package name followed by /sandbox so emdash knows to look for a plugin in src/sandbox-entry.ts
Create an object inside adminWidgets for each widget you plan to add to the dashboard. Each widget needs to have a unique id.
Next create src/sandbox-entry.ts. This is where your plugin's logic will live.
import { definePlugin, type PluginContext, type RouteContext } from "emdash";
export default definePlugin({
hooks: {},
routes: {
admin: {
handler: async (routeCtx: RouteContext, pluginCtx: PluginContext) => {
const interaction = routeCtx.input as {
type: string;
page?: string;
action_id?: string;
value?: string;
};
pluginCtx.log.info("hello admin", interaction);
return { blocks: [] };
},
},
},
});
The admin route will handle all requests on the admin panel. In future steps you will need to replace the log with a condition that builds the UI whenever a widget request is made.
Inside the plugin directory, build your TypeScript files using tsdown. You should see a dist folder appear.
bun run dev
6. Make Emdash use the plugin
Navigate to astro.config.mjs and place helloChartPlugin() inside the plugins array.
import { helloChartPlugin } from "hello-chart-plugin";
...
emdash({
database: d1({ binding: "DB", session: "auto" }),
storage: r2({ binding: "MEDIA" }),
plugins: [formsPlugin(), helloChartPlugin()],
sandboxed: [webhookNotifierPlugin()],
sandboxRunner: sandbox(),
marketplace: "https://marketplace.emdashcms.com",
}),
Afterwards, you may need to restart your dev server if you are encountering errors. In some cases I needed to delete node_modules/.vite to get passed the errors.
If it worked correctly you should see a blank widget on the dashboard and a log in the terminal that looks like the following:
00:21:15 [vite] [plugin:com.lucent.hello-chart-plugin] hello admin { type: 'page_load', page: 'widget:hello-chart' }
The log shows the type of interaction that happened on the admin panel.
7. Add Condition to Build UI
Navigate back to src/sandbox-entry.ts in the plugin's directory. Replace the log with a conditional check for the interaction type and page:
if (
interaction.type === "page_load" &&
interaction.page === "widget:hello-chart"
) {
return buildChartWidget(pluginCtx);
}
Next add the definition for buildChartWidget. You are returning a BlockResponse. You will need to import that type from @emdash-cms/blocks
import type { BlockResponse } from "@emdash-cms/blocks";
function buildChartWidget(ctx: PluginContext): BlockResponse {
return {
blocks: [
{
type: "context",
text: "This chart shows overview of post status.",
},
],
};
}
If everything worked correctly you should see your widget with a paragraph of text.
8. Make the Chart
The last step is to edit buildChartWidget to return a chart block type. Add this after the context block type:
{
type: "chart",
config: {
chart_type: "custom",
options: {
series: [
{
type: "pie",
data: [
{ value: 335, name: "Published" },
{ value: 234, name: "Draft" },
{ value: 120, name: "Scheduled" },
],
},
],
},
height: 300,
},
},
Now you should see a pie chart on the dashboard widget!
Conclusion
Emdash is a work in progress, but you can create a dashboard widget today!





Top comments (0)