bgoosman

bgoosman

It’s easy to create a Kino.frame and render some status text like “Loading” or “Idle”. Ideally I’d like to disable the submit button in my form and display a spinner inside it.

I’m wondering what elixirforum friendly folks do in their Livebooks! :slight_smile:

Showing Posts 1 to 10

joelpaulkoch

joelpaulkoch

Hey, looks like you’re really lucky: Elixir Blog Posts - #1129 by tommica

bgoosman

bgoosman OP

I’m not sure - that blog post was written for Liveview. Is it applicable to Livebook? :thinking:

joelpaulkoch

joelpaulkoch

Oh, you’re right.. I think you could do something similar with Kino.HTML?

bgoosman

bgoosman OP

Yeah, I think Kino.HTML might be it. I could create a reusable spinner component, then render it into a Frame whenever there is some async task.

adammokan

adammokan

There is a little bit of prior art in the form of hex.pm/packages/kino_progress_bar.

Even if it doesn’t meet your needs, it may serve as inspiration for a new solution.

hugobarauna

hugobarauna

Livebook Core Team

You can build your own spinner UI component based on Kino.HTML like that:

defmodule KinoSpinner do
  def new(dimensions \\ "30px") do
    Kino.HTML.new("""
    <div class="loader"></div>

    <style>
      .loader {
        border: 16px solid #f3f3f3; /* Light grey */
        border-top: 16px solid #3498db; /* Blue */
        border-radius: 50%;
        width: #{dimensions};
        height: #{dimensions};
        animation: spin 2s linear infinite;
      }

      @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
    </style>
    """)
  end
end

And use like this in a form:

form =
  Kino.Control.form(
    [
      name: Kino.Input.text("Data", default: "some data to process")
    ],
    submit: "Submit"
  )

output_frame = frame()

Kino.listen(form, fn _event ->
  Kino.Frame.render(output_frame, grid([text("Processing..."), KinoSpinner.new()]))
  Process.sleep(2_000)
  Kino.Frame.render(output_frame, "Processing is done. ✅")
end)

grid([form, output_frame])

Here’s a quick video demo: CleanShot 2024-09-18 at 13.47.38 · CleanShot Cloud

Or you can use a custom kino from the community, like this one from Andrés Alejos:

form =
  Kino.Control.form(
    [
      name: Kino.Input.text("Data", default: "some data to process")
    ],
    submit: "Submit"
  )

output_frame = frame()

Kino.listen(form, fn _event ->
  progress_bar = KinoProgressBar.new(max: 100)
  Kino.Frame.render(output_frame, progress_bar)

  Enum.each(1..100, fn index ->
    KinoProgressBar.update(progress_bar, index, 100)
    Process.sleep(50)
  end)

  Kino.Frame.render(output_frame, "Processing is done. ✅")
end)

grid([form, output_frame])

Here’s a quick video demo: CleanShot 2024-09-18 at 13.49.15 · CleanShot Cloud

Here’s the notebook with both demos: How to display progress using Kino · GitHub

bgoosman

bgoosman OP

Wow, thanks for the high effort post Hugo!

bgoosman

bgoosman OP

~btw I think you meant to write Kino.Frame.new() instead of frame()? Where does frame() come from?~

Nevermind, import Kino.Shorts is the answer.

bgoosman

bgoosman OP

It seems that grid() breaks the <enter> key behavior in the form’s text input. Where should I report that?

hugobarauna

hugobarauna

Livebook Core Team
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews