Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Custom HTML rendering on the card view #513

Closed
estruyf opened this issue Feb 24, 2023 · 13 comments
Closed

Enhancement: Custom HTML rendering on the card view #513

estruyf opened this issue Feb 24, 2023 · 13 comments

Comments

@estruyf
Copy link
Owner

estruyf commented Feb 24, 2023

Allow custom HTML to be rendered on the card view. This allows authors to extend their dashboards/cards experience.

@estruyf estruyf added the enhancement New feature or request label Feb 24, 2023
@estruyf
Copy link
Owner Author

estruyf commented Feb 24, 2023

I started using the https://visitorbadge.io service on my blog to get simple visitor stats per page. That gave me the idea to have a custom renderer that allows me to quickly drop some HTML per card to check these stats on the card/dashboard.

The outcome of this looks as follows:

image

This is not yet implemented; just a POC on my end for now to check the possibilities and what the best way would be to get the HTML on the card view.

@estruyf
Copy link
Owner Author

estruyf commented Feb 24, 2023

Option 1

Reference is like a script, which will be invoked when the card renders; you can use node/bash/... to execute, all you need to return is the HTML string.

Note: This would work similarly like custom actions and post scripts.

Update

It will become option 2. The reason for this is that it is more powerful to create dynamic components and generates less overhead.

@estruyf
Copy link
Owner Author

estruyf commented Feb 24, 2023

Option 2

Ability to reference a JS file that provides a function like getCardHtml, this will be called when the card gets rendered.

Example:

fmExternal = window.fmExternal || {};

fmExternal.getCardHtml = function (filePath, data) {
  console.log('getCardHtml', filePath, data)
  if (data && data.slug) {
    return `<div style="margin-top:0.5rem">html to render</div>`
  }
  return '';
}

Note: with this kind of approach, we might be able to get more functionality and extensibility points in and it would also fit in the marketplace idea. It also has less overhead, as there is no external script execution required.

@estruyf
Copy link
Owner Author

estruyf commented Feb 24, 2023

Investigating option 2, and must say that this has a lot of potential.

Here is an example of how it can be used with, for instance Handlebars

import handlebars from 'https://cdn.skypack.dev/handlebars';

const getHtml = (data) => {
  const source = `
  <div style="margin-top: .5em; font-style: italic;">
    {{title}}
  </div>
  `;

  const template = handlebars.compile(source);
  return template(data);
}

window.fmExternal = window.fmExternal || {};

fmExternal.getCardHtml = async (filePath, data) => {
  return getHtml(data);
}

@estruyf
Copy link
Owner Author

estruyf commented Feb 25, 2023

Question 1

If we would bring this functionality, where would you like to add your HTML?

Thinking of the following zones:

  • Replace the card header/image
  • Add a card footer

Feel free to suggest other zones to which you want to add your HTML.

@estruyf
Copy link
Owner Author

estruyf commented Feb 25, 2023

Registering your extensibility script(s)

"frontMatter.extensibility.scripts": [
  "[[workspace]]/external.js"
],

@estruyf
Copy link
Owner Author

estruyf commented Feb 26, 2023

It is now available in the latest beta, be sure to enable the experimental feature setting: "frontMatter.experimental": true.

Register your script

Add the frontMatter.extensibility.scripts setting, with the path to your script. You can use an external URL (https only), or a file reference within your project. You can use the [[workspace]] placeholder.

The script

All you need to do for the script is register the window.fmExternal.getCardFooter method. Example:

window.fmExternal = window.fmExternal || {};

window.fmExternal.getCardFooter = async (filePath, data) => {
  return `<span>This is the HTML to render</span>`
}

@estruyf
Copy link
Owner Author

estruyf commented Feb 26, 2023

I've just published a new extensibility dependency, which makes registration easier.

Your script its content looks as follows:

import { registerCardFooter } from "https://cdn.skypack.dev/@frontmatter/extensibility";

registerCardFooter(async (filePath, data) => {
  return `<span>Your HTML</span>`;
});

@estruyf
Copy link
Owner Author

estruyf commented Feb 26, 2023

Testing a bit more with lit webcomponents

Screen.Recording.2023-02-26.at.21.27.04.mov

The code

import {
  registerCardFooter
} from "https://cdn.skypack.dev/@frontmatter/extensibility";

import {html, css, LitElement} from 'https://cdn.skypack.dev/lit';

export class SimpleGreeting extends LitElement {
  static styles = css`p { color: #44FFD2 }`;

  static properties = {
    count: {type: Number},
  };

  constructor() {
    super();
    this.count = 0;
  }

  _increment(e) {
    this.count++;
  }

  render() {
    return html`
      <p><button @click="${this._increment}">Click Me!</button></p>
      <p>You've clicked me: ${this.count}!</p>
    `;
  }
}
customElements.define('simple-counter', SimpleGreeting);

registerCardFooter(async (filePath, data) => {
  const slug = encodeURIComponent(data.slug);
  return `
    <simple-counter></simple-counter>
  `;
});

I think this has the potential to allow you to create custom field renderers as well.

@estruyf
Copy link
Owner Author

estruyf commented Feb 27, 2023

Another place could be a custom view panel.

image

@estruyf
Copy link
Owner Author

estruyf commented Feb 27, 2023

💥 CUSTOM FIELDS 💥

Screen.Recording.2023-02-27.at.12.12.33.mov

@estruyf
Copy link
Owner Author

estruyf commented Feb 27, 2023

Examples have been added here: https://github.com/FrontMatter/extensibility

@estruyf
Copy link
Owner Author

estruyf commented Feb 28, 2023

With the enableDevelopmentMode method from the extensibility dependency, you can turn on the development mode.

This allows you to quickly reload the webview without the need to reload vscode or close and open the dashboard again and again.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant