Skip to content

Instantly share code, notes, and snippets.

@laszlokorte
Created January 27, 2026 23:17
Show Gist options
  • Select an option

  • Save laszlokorte/67b0c4a81eb105d27da50d2c03f72786 to your computer and use it in GitHub Desktop.

Select an option

Save laszlokorte/67b0c4a81eb105d27da50d2c03f72786 to your computer and use it in GitHub Desktop.
Phoenix Single file app
Mix.install([
{:phoenix_playground, "~> 0.1.8"}
])
defmodule SpinnerComponent do
use Phoenix.LiveComponent
def mount(socket) do
{:ok, assign(socket, count: 0)}
end
defp classes(classes \\ []) do
classes
|> Enum.filter(&elem(&1, 1))
|> Enum.map(&elem(&1, 0))
|> Enum.join(" ")
end
def render(assigns) do
~H"""
<span class={classes(spinner: true, positive: @count > 0, negative: @count < 0)}>
<button phx-click="remove-element" value={"#{ @id }"}>&times;</button>
<button phx-click="dec" phx-target={"#{ @myself }"}>-</button>
<output class="spinner-value"><%= @count %></output>
<button phx-click="inc" phx-target={"#{ @myself }"}>+</button>
</span>
"""
end
def handle_event("inc", _params, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
def handle_event("dec", _params, socket) do
{:noreply, update(socket, :count, &(&1 - 1))}
end
end
defmodule DemoLive do
use Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok, assign(socket, spinners: [])}
end
def render(assigns) do
~H"""
<h1>Phoenix Spinner List Demo</h1>
<div class="list">
<.live_component :for={s <- @spinners} module={SpinnerComponent} id={"spinner-#{s}"} />
<button phx-click="add-spinner">Add spinner</button>
</div>
<style type="text/css">
body {
padding: 1em;
margin: 0;
font-family: monospace;
}
h1 {
margin: 0 0 1em;
}
button {
font: inherit;
padding: 0.5ex 1ex;
vertical-align: center;
border: none;
display: flex inline;
align-items: center;
background-color: #111;
color: #fff;
cursor: pointer;
text-align: center;
justify-content: center;
}
button:hover {
background-color: #1f1f1f;
}
button:active {
background-color: #000;
}
.spinner {
display: flex inline;
gap: 1ex;
align-items: baseline;
justify-content: space-between;
padding: 4px;
background: #ddd;
}
.spinner.positive {
background-color: #cfc;
}
.spinner.negative {
background-color: #fcc;
}
.spinner-value {
flex: 2em 1 0;
text-align: center;
}
.list {
display: flex;
width: max-content;
flex-direction: column-reverse;
gap: 2px;
}
.list > :last-child {
position: sticky;
padding: 2ex 2em;
top: 1em
}
</style>
"""
end
def handle_event("add-spinner", _params, socket) do
{:noreply, update(socket, :spinners, &[Integer.to_string(Enum.count(&1)) | &1])}
end
def handle_event("remove-element", %{"value" => "spinner-" <> id}, socket) do
{:noreply, update(socket, :spinners, &Enum.filter(&1, fn x -> x != id end))}
end
end
PhoenixPlayground.start(live: DemoLive)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment