Skip to content

Instantly share code, notes, and snippets.

@hugobarauna
Last active April 9, 2024 15:06
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hugobarauna/69f0e8b4715b54d875eecafbc0b7f2b0 to your computer and use it in GitHub Desktop.
Save hugobarauna/69f0e8b4715b54d875eecafbc0b7f2b0 to your computer and use it in GitHub Desktop.
Kino JSON input with syntax highlight

Kino JSON Input Proof of Concept

Mix.install([
  {:kino, "~> 0.12.3"},
  {:jason, "~> 1.4"}
])

Section

defmodule KinoJsonInput do
  use Kino.JS
  use Kino.JS.Live

  def new(code) do
    Kino.JS.Live.new(__MODULE__, code)
  end

  def read(kino) do
    Kino.JS.Live.call(kino, :read)
  end

  @impl true
  def init(code, ctx) do
    {:ok, assign(ctx, code: code)}
  end

  @impl true
  def handle_connect(ctx) do
    {:ok, ctx.assigns.code, ctx}
  end

  @impl true
  def handle_event("update_code", code, ctx) do
    {:noreply, assign(ctx, code: code)}
  end

  @impl true
  def handle_call(:read, _from, ctx) do
    {:reply, ctx.assigns.code, ctx}
  end

  asset "main.js" do
    """
    export async function init(ctx, code) {
      await ctx.importCSS("https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css");
      await ctx.importJS("https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js");
      await ctx.importJS("https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js");

      await ctx.importCSS("https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.2/code-input.min.css");
      await ctx.importJS("https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.2/code-input.min.js");
      await ctx.importJS("https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.2.1/plugins/indent.min.js");


      // This is needed because the CodeInput lib is activated
      // on window.load (https://github.com/WebCoder49/code-input/blob/v2.2.1/code-input.js#L983-L985)
      // but by the time this JS code is executed, the original load event has already been fired.
      window.dispatchEvent(new Event("load"));


      codeInput.registerTemplate("syntax-highlighted", codeInput.templates.prism(Prism, [new codeInput.plugins.Indent()]));

      ctx.root.innerHTML = `
        <code-input id="input-json" language="json" template="syntax-highlighted" placeholder="JSON">${code}</code-input>
      `;

      const codeInputEl = document.getElementById("input-json");

      codeInputEl.addEventListener("change", (event) => {
        ctx.pushEvent("update_code", event.target.value);
      });
    }
    """
  end
end
kino_json_input = KinoJsonInput.new("")
if KinoJsonInput.read(kino_json_input) == "" do
  Kino.interrupt!(:normal, "fill in the JSON input")
end
import Kino.Shorts
json =
  kino_json_input
  |> KinoJsonInput.read()
  |> Jason.decode!()

grid([
  markdown("### Here's the preview of your JSON"),
  Kino.Tree.new(json)
])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment