npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@frontmatter/extensibility

v0.0.18

Published

Front Matter CMS extensibility library

Downloads

423

Readme

Front Matter CMS - Extensibility module

This module provides a way to extend the CMS its UI with custom functionality, and it provides helpers for creating your custom content or media scripts.

Custom scripts

To make it easier to create your custom scripts, you can make use of the @frontmatter/extensibility module its ContentScript, MediaScript, and PlaceholderScript classes.

Content scripts

If you want to write a script for content management in Front Matter CMS, you can make use of the ContentScript class. This class provides methods to retrieve the arguments, ask questions, and let the script know its done.

Get arguments

To retrieve all arguments, you can use the getArguments method.

import { ContentScript } from '@frontmatter/extensibility';

const { command, scriptPath, workspacePath, filePath, frontMatter, answers } = ContentScript.getArguments();

Ask questions

To ask a question to the user in the CMS, you can use the askQuestions method:

if (!answers) {
  MediaScript.askQuestions([{
    name: "customId",
    message: "Which ID do you want to use?",
    default: ""
  }]);
  return;
}

In case you want to have a multi-select question, you can just add the options to the question:

if (!answers) {
  MediaScript.askQuestions([{
    name: "category",
    message: "Which category do you want to use?",
    options: [
      "Category 1",
      "Category 2",
      "Category 3"
    ]
  }]);
  return;
}

Important: Front Matter will execute the same script, so you first need to check if the answers were provided.

You can retrieve the answer from the answers object:

const customId = answers.customId;

Update front matter

To let the CMS know you want to update the article its front matter, you can make use of the updateFrontMatter method:

ContentScript.updateFrontMatter({
  "field": "value"
});

Open a file or page on completion

To let the CMS know you want to open a file or page after the script is done, you can make use of the open method:

// Open a URL
ContentScript.open("https://frontmatter.codes");

// Or open a file
ContentScript.open("./path/to/file.md");

Done

To let the CMS know you are done with your script, you can make use of the done method:

ContentScript.done("The script is done");

Media scripts

The MediaScript class provides the same functionality as the ContentScript class, but it is used for media management scripts. There are a couple differences:

  • Arguments will not provide the frontMatter object;
  • You cannot make use of the updateFrontMatter method.

Additionally, they provide the following methods:

  • MediaScript.copyMetadata(source, destination): This method will copy the metadata from the source file to the destination file.
  • MediaScript.copyMetadataAndDelete(source, destination); This method will copy the metadata from the source file to the destination file and delete the source file.
  • MediaScript.delete(source): This method will delete the source file.

Placeholder scripts

The PlaceholderScript class provides the same functionality as the ContentScript class, but it is used for placeholders which can be used on content creation. The main difference between the ContentScript and PlaceholderScript is that it will not provide the frontMatter object. Instead it returns the title of the page.

UI extensibility

Content dashboard

Card extensibility points:

  • Image
  • Footer

Extension version 9.0.0 and higher:

  • Draft status
  • Date
  • Title
  • Description
  • Tags

Panel

  • Custom panel view
  • Custom fields

Usage

You can make use of ESM modules in order to make use of the extensibility dependency. We recommend to use the CDN from Skypack or jsdelivr.

URLs:

  • https://cdn.skypack.dev/@frontmatter/extensibility
  • https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm
  • https://esm.run/@frontmatter/extensibility

Development mode

Turn on the development mode in order to quickly reload the webviews (panel + dashboard) when you make changes to the code.

import { enableDevelopmentMode } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

enableDevelopmentMode();

Registering a card image

import { registerCardImage } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardImage(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering the card draft status

import { registerCardStatus } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardStatus(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering the card date

import { registerCardDate } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardDate(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering the card title

import { registerCardTitle } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardTitle(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering the card description

import { registerCardDescription } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardDescription(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering the card tags

import { registerCardTags } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardTags(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering a card footer

import { registerCardFooter } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {string} filePath - The path of the file
 * @param {object} data - The metadata of the file
 * @returns {string} - The HTML to be rendered in the card footer
 */
registerCardFooter(async (filePath, metadata) => {
  return `<span>Your HTML</span>`;
});

Registering a panel view

import { registerPanelView } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";

/**
 * @param {object} data - The metadata of the file
 * @returns {object} - The view to be rendered in the panel
 */
registerPanelView(async (metadata) => {
  return {
    title: "Custom View",
    content: `
      <div>
        <h1>Custom view...</h1>
        <p>Here you can add your own custom view.</p>
      </div>
    `,
  };
});

Registering a custom field

The following example makes use of lit to render a custom field, by creating a web component, it makes it easier to have more control over the field.

import { registerCustomField } from "https://cdn.jsdelivr.net/npm/@frontmatter/extensibility/+esm";
import { css, html, LitElement } from "https://esm.run/lit";

let CustomFieldValueChange;

class CustomField extends LitElement {
  static styles = css`
    input {
      border: 1px solid transparent;
      box-sizing: border-box;
      font-family: var(--vscode-font-family);
      padding: var(--input-padding-vertical) var(--input-padding-horizontal);
      color: var(--vscode-input-foreground);
      outline: none;
      background-color: var(--vscode-input-background);
      width: 100%;
    }

    input:focus {
      border: 1px solid var(--vscode-inputValidation-infoBorder);
    }
  `;

  static properties = {
    inputValue: {
      type: String,
    },
  };

  constructor() {
    super();
    this.inputValue = "";
  }

  _internalChange(e) {
    this.inputValue = e.target.value;
    CustomFieldValueChange(e.target.value);
  }

  render() {
    return html`
      <input
        type="text"
        value="${this.inputValue}"
        @change=${(e) => this._internalChange(e)}
      />
    `;
  }
}
customElements.define("custom-field", CustomField);

/**
 * @param {string} name - The name of the custom field to use in the content-type
 * @param {function} callback - The callback that will be used for rendering the custom field
 */
registerCustomField("customField", async (value, onChange) => {
  // Bind the event handler for the onChange evet
  CustomFieldValueChange = onChange;
  // Return the HTML of the custom field
  return `
    <custom-field inputValue="${value || ""}"></custom-field>
  `;
});

Issues

Please report any issues you find in the Front Matter CMS issue list.