DEV Community

Zeb
Zeb

Posted on

How to Make Emdash Pie Chart Widget

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

you will need to install a few dependencies for this plugin to work:

bun add emdash --peer
bun add -D tsdown @emdash-cms/blocks
Enter fullscreen mode Exit fullscreen mode

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"],
  },
});
Enter fullscreen mode Exit fullscreen mode

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:*"
},
Enter fullscreen mode Exit fullscreen mode

Next finish linking the plugin by running:

bun install
Enter fullscreen mode Exit fullscreen mode

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" }],
  };
}
Enter fullscreen mode Exit fullscreen mode

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: [] };
      },
    },
  },
});

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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",
}),
Enter fullscreen mode Exit fullscreen mode

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' }
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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.",
      },
    ],
  };
}
Enter fullscreen mode Exit fullscreen mode

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,
  },
},
Enter fullscreen mode Exit fullscreen mode

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)