LoginSignup
9
5

Phoenix LiveView に超簡単 UI コンポーネント Pines を導入する

Last updated at Posted at 2023-08-15

はじめに

前回の記事で Pines を紹介しました

Pines はコピー&ペーストだけでアコーディオンやバナーなどの UI コンポーネントを実装できるライブラリーです

See the Pen Pines Accordion by Ryo Wakabayashi (@ryowakabayashi) on CodePen.

See the Pen Untitled by Ryo Wakabayashi (@ryowakabayashi) on CodePen.

See the Pen Untitled by Ryo Wakabayashi (@ryowakabayashi) on CodePen.

See the Pen Pines Copy to Clipboard by Ryo Wakabayashi (@ryowakabayashi) on CodePen.

Alpine.js や Tailwind CSS を利用しているため、 JS や CSS をほとんど書くことなく綺麗に動く UI が作れてしまいます

Alpine.js と Tailwind CSS でピンと来た方もいると思いますが、 Pines は Elixir の Web フレームワークである Phoeix と非常に相性が良いです

この記事では Phoenix への Pines コンポーネント導入方法を紹介します

なお、 Phoenix のバージョンは 1.7 を想定しています

実装したコードの全量はこちら

実行環境

M2 Mac 上に asdf でインストールした環境を使いました

他の環境でも特に問題ないと思いますが、 Elixir は 1.12 以降(Phoenix LiveView の要件)を使いましょう

  • macOS Ventura 13.5
  • Elixir 1.15.4
  • Erlang 26.0.2
  • Node.js 20.5.0
  • Yarn 1.22.19

Phoenix プロジェクトの準備

Pines を導入する Phoenix プロジェクトを準備します

公式ドキュメントに従って作業していきます

Hex のインストール

Elixir のパッケージマネージャーである Hex をインストールします

mix local.hex

Phoenix のインストール

Phoenix をインストールします

mix archive.install hex phx_new

プロジェクトの作成

新しい Phoenix プロジェクトを作成します

mix phx.new pines_sample --no-ecto

今回の例ではデータベースを使わないので --no-ecto を指定しています

実際のプロジェクトの場合は必要に応じて変更してください

しばらくすると Fetch and install dependencies? [Yn] と尋ねられるのでそのまま Enter キーを押してください

Phoenix プロジェクトの雛形が作成され、デフォルトで必要なライブラリーが取得されます

作成したプロジェクトのディレトリー内に移動します

cd pines_sample

Alpine.js の導入

Phoenix 1.7 では Tailwind CSS がデフォルトで導入されているため、 Alpine.js だけ手動で導入します

まず、プロジェクト内の assets ディレクトリーに移動します

cd assets

そして、 JavaScript の依存ライブラリーとして Alpine.js を追加します

ついでにアニメーションを実装するための Collapse Plugin も追加しておきましょう

yarn add alpinejs @alpinejs/collapse

コマンドを実行すると "assets/package.json" が追加され、 "assets/node_modules" 内に依存ライブラリーがインストールされます

"assets/package.json" の中身は以下のようになります

{
  "dependencies": {
    "@alpinejs/collapse": "^3.12.3",
    "alpinejs": "^3.12.3"
  }
}

続いて "assets/js/app.js" に Alpine.js の読み込み処理を追加します

// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
import "phoenix_html"
// Establish Phoenix Socket and LiveView configuration.
import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"

+ import Alpine from "alpinejs"
+ import collapse from '@alpinejs/collapse'

+ Alpine.plugin(collapse)
+ window.Alpine = Alpine
+ Alpine.start()

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
- let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
+ let liveSocket = new LiveSocket("/live", Socket, {
+     params: {_csrf_token: csrfToken},
+     dom: {
+       onBeforeElUpdated(from, to) {
+         if (from._x_dataStack) {
+           window.Alpine.clone(from, to)
+         }
+       }
+     }
+ })
...

作業が済んだらプロジェクトのルートに戻っておきましょう

cd ..

コンポーネントの追加

まずカードコンポーネントを作ってみましょう

コンポーネントファイルの作成

"lib/pines_sample_web/components/card.ex" に以下の内容のファイルを作ります

defmodule PinesSampleWeb.Components.Card do
  @moduledoc """
  Card.

  # Example
  <PinesSampleWeb.Components.Card.render />
  """
  use PinesSampleWeb, :live_component

  def render(assigns) do
    ~H"""
    Card
    """
  end
end

これは Phoenix でコンポーネントを作る場合の雛形になっています

H シギル内(H""" から """ の間)が画面に表示される HTML のテンプレートです

コンポーネント表示用画面の作成

コンポーネントを表示するため、 Phoenix LiveView による画面を作成しましょう

Phoenix LiveView では、xxx.ex (動作の定義)と同じ階層に xxx.html.heex (外観のテンプレート)を作成することで画面を実装できます

まず "lib/pines_sample_web/live" ディレクトリーを作成します

"lib/pines_sample_web/live/showcase.ex" を以下の内容で作成します

defmodule PinesSampleWeb.Showcase do
  use PinesSampleWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def handle_event("card_button_clicked", _, socket) do
    IO.inspect("card_button_clicked")
    {:noreply, socket}
  end
end

また、"lib/pines_sample_web/live/showcase.html.heex" を以下の内容で作成します

<div class="w-full">
  <div class="m-4">
    <p class="text-xl font-bold mb-4">Card</p>
    <div class="flex items-center justify-center p-8 border border-nuetral-300 rounded-md">
      <PinesSampleWeb.Components.Card.render />
    </div>
  </div>
</div>

Router の設定

"lib/pines_sample_web/router.ex" を以下のように編集します

...
  scope "/", PinesSampleWeb do
    pipe_through :browser

    get "/", PageController, :home
  end
+
+  scope "/" do
+   pipe_through :browser
+
+   live "/live", PinesSampleWeb.Showcase
+ end
...

これにより、 http://localhost:4000/live にアクセスすることで PinesSampleWeb.Showcase の画面が表示されるようになります

Phoeix の起動

以下のコマンドを実行し、 Phoenix を起動します

mix phx.server

以下のような結果が表示されます

Compiling 14 files (.ex)
Generated pines_sample app
[info] Running PinesSampleWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http)
[info] Access PinesSampleWeb.Endpoint at http://localhost:4000
[watch] build finished, watching for changes...

Rebuilding...

Done in 144ms.

ブラウザで http://localhost:4000/live を開きます

スクリーンショット 2023-08-14 17.14.43.png

枠の中の "Card" の部分がコンポーネントです

このコンポーネントを改造していきます

Pines のコピー&ペースト

Pines 公式ドキュメントの Card コンポーネントのページを開きます

コピーボタン(下画像の赤枠部分)をクリックし、コードをコピーします

スクリーンショット 2023-08-14 17.17.39.png

"lib/pines_sample_web/components/card.ex" の H シギル内にペーストします

defmodule PinesSampleWeb.Components.Card do
  @moduledoc """
  Card.

  # Example
  <PinesSampleWeb.Components.Card.render />
  """
  use PinesSampleWeb, :live_component

  def render(assigns) do
    ~H"""
    <div class="rounded-lg overflow-hidden border border-neutral-200/60 bg-white text-neutral-700 shadow-sm w-[380px]">
<div class="relative">
<img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2370&q=80" class="w-full h-auto" />
</div>
<div class="p-7">
<h2 class="mb-2 text-lg font-bold leading-none tracking-tight">Product Name</h2>
<p class="mb-5 text-neutral-500">This card element can be used to display a product, post, or any other type of data.</p>
<button class="inline-flex items-center justify-center w-full h-10 px-4 py-2 text-sm font-medium text-white transition-colors rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none bg-neutral-950 hover:bg-neutral-950/90">View Product</button>
</div>
</div>
    """
  end
end

ファイルを上書き保存して http://localhost:4000/live を見ると、下画像のように Pines 公式ドキュメントと全く同じカードが実装できています

スクリーンショット 2023-08-14 17.21.20.png

引数の追加

このままだと固定値を表示するだけなので、変えたい部分を引数にします

更に Phoenix LiveView によるボタンクリック時のイベント phx-click を追加します

また、単純に貼り付けたためにインデントなどが狂っているので修正します

defmodule PinesSampleWeb.Components.Card do
  @moduledoc """
  Card.

  # Example
  <PinesSampleWeb.Components.Card.render
    img_src="https://www.phoenixframework.org/images/blog/1.7-released-e6dc45801b961cb0bb04e6e2a907fbc4.png?vsn=d"
    title="Card"
    message="Card message"
    button_text="Button"
    button_event="card_button_clicked"
  />
  """
  use PinesSampleWeb, :live_component

  attr :img_src, :string, default: ""
  attr :title, :string, default: ""
  attr :message, :string, default: ""
  attr :button_text, :string, default: "Click"
  attr :button_event, :string, default: "card_button_clicked"

  def render(assigns) do
    ~H"""
    <div class="rounded-lg overflow-hidden border border-neutral-200/60 bg-white text-neutral-700 shadow-sm w-[380px]">
      <div class="relative">
        <img src={@img_src} class="w-full h-auto" />
      </div>
      <div class="p-7">
        <h2 class="mb-2 text-lg font-bold leading-none tracking-tight">
          <%= @title %>
        </h2>
        <p class="mb-5 text-neutral-500">
          <%= @message %>
        </p>
        <button
          class="inline-flex items-center justify-center w-full h-10 px-4 py-2 text-sm font-medium text-white transition-colors rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none bg-neutral-950 hover:bg-neutral-950/90"
          phx-click={@button_event}
        >
          <%= @button_text %>
        </button>
      </div>
    </div>
    """
  end
end

attr から始まっている行が引数です

以下の4つを引数として追加しています

  • img_src: 画像 URL
  • title: カードのタイトル
  • message: カードの本文
  • button_text: カードのボタン文言
  • button_event: カードのボタンクリックイベント

<img src={@img_src} class="w-full h-auto" /> のように HTML のタグ内で <属性>={@<引数名>} とすることで引数の値をタグの属性に渡せます

また、 <%= @<引数名> %> で画面上に引数の値を表示できます

phx-click={@button_event} により、コンポーネントを使う画面の handle_event 関数でイベントを処理できるようになります

各引数はデフォルト値を設定しているため、この時点で http://localhost:4000/live は以下のような表示になります

スクリーンショット 2023-08-14 17.31.23.png

"lib/pines_sample_web/live/showcase.html.heex" を以下の内容に編集しましょう

<div class="w-full">
  <div class="m-4">
    <p class="text-xl font-bold mb-4">Card</p>
    <div class="flex items-center justify-center p-8 border border-nuetral-300 rounded-md">
      <PinesSampleWeb.Components.Card.render
        img_src="https://www.phoenixframework.org/images/blog/1.7-released-e6dc45801b961cb0bb04e6e2a907fbc4.png?vsn=d"
        title="Card"
        message="Card message"
        button_text="Button"
        button_event="card_button_clicked"
      />
    </div>
  </div>
</div>

コンポーネントに引数の値が渡され、 http://localhost:4000/live は以下のような表示になります

スクリーンショット 2023-08-14 17.34.07.png

また、ボタンをクリックすると Phoenix を起動したターミナルに以下のようなログが表示され、イベントを処理できていることが確認できます

"card_button_clicked"
[debug] HANDLE EVENT "card_button_clicked" in PinesSampleWeb.Showcase
  Parameters: %{"value" => ""}
[debug] Replied in 503µs

これで Phoenix LiveView に Pines のカードコンポーネントを追加できました

アコーディオンの追加

カードと同様にアコーディオンを追加します

"lib/pines_sample_web/components/accordion.ex" を以下の内容で作成します

defmodule PinesSampleWeb.Components.Accordion do
  @moduledoc """
  Accordion.

  # Example
  <PinesSampleWeb.Components.Accordion.render />
  """
  use PinesSampleWeb, :live_component

  def render(assigns) do
    ~H"""
    Accordion
    """
  end
end

H シギルの中に Pines 公式ドキュメントからアコーディオンのコードをコピー&ペーストします

ただし、コードに含まれる :class= の文言がエラーになるため、 :class=x-bind:class= に一括置換します

defmodule PinesSampleWeb.Components.Accordion do
  @moduledoc """
  Accordion.

  # Example
  <PinesSampleWeb.Components.Accordion.render />
  """
  use PinesSampleWeb, :live_component

  def render(assigns) do
    ~H"""
    <div x-data="{
      activeAccordion: '',
      setActiveAccordion(id) {
          this.activeAccordion = (this.activeAccordion == id) ? '' : id
      }
  }" class="relative w-full mx-auto overflow-hidden text-sm font-normal bg-white border border-gray-200 divide-y divide-gray-200 rounded-md">
  <div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
      <button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
          <span>What is Pines?</span>
          <svg class="w-4 h-4 duration-200 ease-out" x-bind:class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
      </button>
      <div x-show="activeAccordion==id" x-collapse x-cloak>
          <div class="p-4 pt-0 opacity-70">
              Pines is a UI library built for AlpineJS and TailwindCSS.
          </div>
      </div>
  </div>
  <div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
      <button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
          <span>How do I install Pines?</span>
          <svg class="w-4 h-4 duration-200 ease-out" x-bind:class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
      </button>
      <div x-show="activeAccordion==id" x-collapse x-cloak>
          <div class="p-4 pt-0 opacity-70">
              Add AlpineJS and TailwindCSS to your page and then copy and paste any of these elements into your project.
          </div>
      </div>
  </div>
  <div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
      <button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
          <span>Can I use Pines with other libraries or frameworks?</span>
          <svg class="w-4 h-4 duration-200 ease-out" x-bind:class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
      </button>
      <div x-show="activeAccordion==id" x-collapse x-cloak>
          <div class="p-4 pt-0 opacity-70">
              Absolutely! Pines works with any other library or framework. Pines works especially well with the TALL stack.
          </div>
      </div>
  </div>
</div>
    """
  end
end

アコーディオンを画面上に追加するため、 "lib/pines_sample_web/live/showcase.html.heex" を以下のように編集します

<div class="w-full">
+ <div class="m-4">
+   <p class="text-xl font-bold mb-4">Accordion</p>
+   <div class="p-8 border border-nuetral-300 rounded-md">
+     <PinesSampleWeb.Components.Accordion.render />
+   </div>
+ </div>
  <div class="m-4">
...
</div>

これにより、 http://localhost:4000/live にアコーディオンが追加できました

スクリーンショット 2023-08-15 2.28.09.png

アコーディオンへの引数追加

アコーディオンも引数によって内容を制御できるようにしましょう

"lib/pines_sample_web/components/accordion.ex" を以下の内容に変更します

defmodule PinesSampleWeb.Components.Accordion do
  @moduledoc """
  Accordion.

  # Example
  <PinesSampleWeb.Components.Accordion.render accordions={@accordions} />
  """
  use PinesSampleWeb, :live_component

  attr :accordions, :list

  def render(assigns) do
    ~H"""
    <div x-data="{
      activeAccordion: '',
      setActiveAccordion(id) {
        this.activeAccordion = (this.activeAccordion == id) ? '' : id
      }
    }" class="relative w-full mx-auto overflow-hidden text-sm font-normal bg-white border border-gray-200 divide-y divide-gray-200 rounded-md">
      <%= for accordion <- @accordions do %>
        <div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
          <button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
            <span><%= accordion.title %></span>
            <svg class="w-4 h-4 duration-200 ease-out" x-bind:class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
          </button>
          <div x-show="activeAccordion==id" x-collapse x-cloak>
            <div class="p-4 pt-0 opacity-70">
              <%= accordion.message %>
            </div>
          </div>
        </div>
      <% end %>
    </div>
    """
  end
end

アコーディオンの中に表示するタイトルとメッセージを List で渡すようにしました

"lib/pines_sample_web/live/showcase.ex" を以下のように編集します

defmodule PinesSampleWeb.Showcase do
  use PinesSampleWeb, :live_view

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:accordions, [
        %{
          title: "Accordion 1",
          message: "Message 1"
        },
        %{
          title: "Accordion 2",
          message: "Message 2"
        },
        %{
          title: "Accordion 3",
          message: "Message 3"
        }
      ])

    {:ok, socket}
  end

  def handle_event(event, _, socket) do
    IO.inspect(event)
    {:noreply, socket}
  end
end

また、 "lib/pines_sample_web/live/showcase.html.heex" を以下のように編集します

<div class="w-full">
  <div class="m-4">
    <p class="text-xl font-bold mb-4">Accordion</p>
    <div class="p-8 border border-nuetral-300 rounded-md">
      <PinesSampleWeb.Components.Accordion.render accordions={@accordions} />
    </div>
  </div>
...

これにより、 "showcase.ex" で定義したアコーディオンの内容をコンポーネントに渡すことができます

http://localhost:4000/live を開くと、アコーディオンの内容が変化しました

スクリーンショット 2023-08-15 2.37.34.png

ボタンの実装

ここまでと同じ容量でボタンコンポーネントを作りましょう

Pines 公式ドキュメントでボタンコンポーネントの上から2番目の色付きボタンを実装します

スクリーンショット 2023-08-15 20.59.24.png

"lib/pines_sample_web/components/button.ex" を以下の内容で作成します

今回は最終的な引数追加まで含めた結果だけ以下に示しています

defmodule PinesSampleWeb.Components.Button do
  @moduledoc """
  Button.

  # Example
  <PinesSampleWeb.Components.Button.render text="Click" bg_color="blue" event="button_clicked" />
  """
  use PinesSampleWeb, :live_component

  attr :text, :string
  attr :bg_color, :string, default: "white"
  attr :event, :string, default: "button_clicked"

  def render(assigns) do
    {bg_color, border_color, hover_bg_color, focus_ring_color, color} =
      case assigns.bg_color do
        "blue" -> {"bg-blue-600", "", "hover:bg-blue-700", "focus:ring-blue-700", "text-white"}
        "red" -> {"bg-red-600", "", "hover:bg-red-700", "focus:ring-red-700", "text-white"}
        "green" -> {"bg-green-600", "", "hover:bg-green-700", "focus:ring-green-700", "text-white"}
        "yellow" -> {"bg-yellow-500", "", "hover:bg-yellow-600", "focus:ring-yellow-600", "text-white"}
        _ -> {"bg-white", "border border-neutral-200/70", "hover:bg-neutral-100", "focus:ring-neutral-200/60", "text-neutral-500"}
      end

    assigns =
      assigns
      |> assign(:bg_color, bg_color)
      |> assign(:border_color, border_color)
      |> assign(:hover_bg_color, hover_bg_color)
      |> assign(:focus_ring_color, focus_ring_color)
      |> assign(:color, color)

    ~H"""
    <button
      type="button"
      class={"inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide #{@color} transition-colors duration-200 #{@bg_color} rounded-md #{@border_color} #{@hover_bg_color} focus:ring-2 focus:ring-offset-2 #{@focus_ring_color} focus:shadow-outline focus:outline-none"}
      phx-click={@event}
    >
      <%= @text %>
    </button>
    """
  end
end

少しややこしくなっていますが、以下のコードで引数の bg_color に応じて、背景色、ボーダー色、ホバー時の背景色、フォーカス時に出る枠線の色、文字色を切り替えるように実装しています

    {bg_color, border_color, hover_bg_color, focus_ring_color, color} =
      case assigns.bg_color do
        "blue" -> {"bg-blue-600", "", "hover:bg-blue-700", "focus:ring-blue-700", "text-white"}
        "red" -> {"bg-red-600", "", "hover:bg-red-700", "focus:ring-red-700", "text-white"}
        ...

ここで注意しなければならないのが、必ず hover:bg-neutral-100 のようにクラス名全体を変数に入れることです

Tailwind CSS は実際に使われたクラス名にしかスタイルシートを生成しません

そのため、 hover: が共通だからといって変数に含めない場合、 Tailwind CSS が hover:bg-neutral-100 のスタイルシートを生成せず、ホバーしても色が変化しません

関数内の変数をソケットにアサインしています

(変数を H シギル内に直接渡すと LiveView による変更が反映されません)

    assigns =
      assigns
      |> assign(:bg_color, bg_color)
      |> assign(:border_color, border_color)
      ...

クラス名(Tailwind CSS によるスタイル)をソケット内の値で置き換える場合、以下のように class={"..."} としてダブルクォーテーションの外を {} で囲い、ソケットの各キーを #{} で囲います

      class={"... #{@color} ... #{@bg_color} ..."}

ボタンを画面に表示しましょう

"lib/pines_sample_web/live/showcase.ex" を以下のように編集します

defmodule PinesSampleWeb.Showcase do
  use PinesSampleWeb, :live_view

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:accordions, [
        %{
          title: "Accordion 1",
          message: "Message 1"
        },
        %{
          title: "Accordion 2",
          message: "Message 2"
        },
        %{
          title: "Accordion 3",
          message: "Message 3"
        }
      ])
      |> assign(:buttons, [
        %{
          text: "Button 1",
          bg_color: "white",
          event: "button_1_clicked"
        },
        %{
          text: "Button 2",
          bg_color: "blue",
          event: "button_2_clicked"
        },
        %{
          text: "Button 3",
          bg_color: "red",
          event: "button_3_clicked"
        },
        %{
          text: "Button 4",
          bg_color: "green",
          event: "button_4_clicked"
        },
        %{
          text: "Button 5",
          bg_color: "yellow",
          event: "button_5_clicked"
        },
      ])

    {:ok, socket}
  end

  def handle_event(event, _, socket) do
    IO.inspect(event)
    {:noreply, socket}
  end
end

"lib/pines_sample_web/live/showcase.html.heex" を以下のように編集します

<div class="w-full">
  <div class="m-4">
    <p class="text-xl font-bold mb-4">Button</p>
    <div class="flex items-center justify-center space-x-4 p-8 border border-nuetral-300 rounded-md">
      <%= for button <- @buttons do %>
        <PinesSampleWeb.Components.Button.render
          text={button.text}
          bg_color={button.bg_color}
          event={button.event}
        />
      <% end %>
    </div>
  </div>
...

http://localhost:4000/live に以下のようにボタンが追加されます

スクリーンショット 2023-08-15 21.25.42.png

まとめ

Pines を使うことで、 Phoenix LiveView にも簡単にコンポーネントを追加できました

Pines 公式ドキュメントには他にも様々なコンポーネントが紹介されているので、そこからどんどんコピー&ペーストしましょう

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5