skip to Main Content

Background

I have a small Phoenix 1.7 app where I am trying to add a radial progress bar, using the default TailwindUI components: https://tailwindui.com/components

Unfortunately for me, I was only able to find normal progress bars:

https://flowbite.com/docs/components/progress/

Namely:

<div class="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
  <div class="bg-blue-600 h-2.5 rounded-full" style="width: 45%"></div>
</div>

The only radial progress bar I found was one using DaisyUI:

https://daisyui.com/components/radial-progress/

However, I want to avoid installing anything extra, I really just want to use the default tailwindUI and tailwindCSS that come with Phoenix 1.7

Questions

  1. Does someone know how to create a a radial progress bar component using the default setup that comes with Phoenix LiveView 1.7?
  2. Am I missing some component that already does this?

2

Answers


  1. Chosen as BEST ANSWER

    Answer

    By checking some examples using Tailwind with Apline.js I was able to analyze the code and create a component that does exactly what I want.

    This code uses only Phoniex LiveView vanilla, no extra CSS no extra anything !

    core_components:

      @doc """
      Renders a progress bar for an ongoing operation.
    
      ## Examples
    
          <.progress_bar hidden=false progress=15 />
          <.progress_bar hidden=false progress=20 message="Activating system ..." />
          <.progress_bar hidden=false class="cool-bar" />
      """
      attr :hidden, :boolean, default: true, doc: "whether or not to show the progress bar"
      attr :progress, :integer, default: 0, doc: "the current progress of the bar"
      attr :message, :string, default: "Operation in progress ...", doc: "the message to show while the bar is progressing"
      attr :class, :string, default: nil
    
      def progress_bar(assigns) do
    
        assigns = assign(assigns, :circumference, 2 * 22 / 7 * 120)
        assigns = assign(assigns, :offset, assigns.circumference - assigns.progress / 100 * assigns.circumference)
    
        ~H"""
        <div class={@class} hidden={@hidden}>
          <div class="flex items-center justify-center">
            <p class="text-lg font-semibold"><%= @message %></p>
          </div>
    
          <div class="flex items-center justify-center">
            <svg class="transform -rotate-90 w-72 h-72">
                <circle cx="145" cy="145" r="120" stroke-width="30" fill="transparent" class="stroke-gray-700" />
    
                <circle cx="145" cy="145" r="120" stroke-width="30" fill="transparent"
                    stroke-dasharray={@circumference}
                    stroke-dashoffset={@offset}
                    class="stroke-indigo-500" />
            </svg>
            <span class="absolute text-5xl stroke-black"><%= @progress %></span>
          </div>
    
        </div>
        """
      end
    

    Usage in my_app_live.heex.html:

    <div class="min-h-full max-w-full mx-auto py-6 sm:px-6 lg:px-8">
      <.progress_bar hidden={false} progress={40} message="Activating system ..." />
    </div>
    

    Will produce the following:

    enter image description here

    For more information on how I created this, feel free to check the whole story on the elixir's forum thread:

    https://elixirforum.com/t/radial-progress-bar-using-tailwinui/58098/10?u=fl4m3ph03n1x


  2. I think you may have to write some custom CSS and spice it up with your tailwind classes.

    You can check this gist for a custom-made circular progress bar using Tailwind.

    Basically, here’s what you need:

    // custom.css
    
    .progress-ring__circle {
      stroke-dasharray: 400, 400;
      transition: stroke-dashoffset 0.35s;
      transform: rotate(-90deg);
      transform-origin: 50% 50%;
    }
    
    
    // component.html 
    <div class="relative w-40 h-40">
      <svg class="w-full h-full" viewBox="0 0 100 100">
        <!-- Background circle -->
        <circle
          class="text-gray-200 stroke-current"
          stroke-width="10"
          
          cx="50"
          cy="50"
          r="40"
          fill="transparent"
        ></circle>
        <!-- Progress circle -->
        <circle
          class="text-indigo-500  progress-ring__circle stroke-current"
          stroke-width="10"
          stroke-linecap="round"
          cx="50"
          cy="50"
          r="40"
          fill="transparent"
          stroke-dashoffset="calc(400 - (400 * 45) / 100)"
        ></circle>
        
        <!-- Center text -->
        <text x="50" y="50" font-family="Verdana" font-size="12" text-anchor="middle" alignment-baseline="middle">70%</text>
    
      </svg>
    </div>
    

    I hope this helps. Goodluck!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search