Packages

Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.

Current section

Files

Jump to
raxol lib mix tasks raxol.demo.ex
Raw

lib/mix/tasks/raxol.demo.ex

defmodule Mix.Tasks.Raxol.Demo do
@moduledoc """
Runs built-in Raxol demo applications.
## Usage
mix raxol.demo # Interactive demo picker
mix raxol.demo counter # Simple counter
mix raxol.demo todo # Todo list
mix raxol.demo dashboard # Live BEAM dashboard
mix raxol.demo showcase # Component showcase
mix raxol.demo --list # List available demos
## Demos
* `counter` - Simple counter with +/- keys and buttons
* `todo` - Todo list with add/delete/toggle and input modes
* `dashboard` - Live BEAM dashboard with scheduler, memory, process stats
* `showcase` - Interactive component showcase with 5 tabbed sections
"""
use Mix.Task
@shortdoc "Run built-in Raxol demo applications"
@demos [
{"counter", Raxol.Demo.Counter, "Simple counter with +/- keys and buttons"},
{"todo", Raxol.Demo.Todo,
"Todo list with add/delete/toggle and input modes"},
{"dashboard", Raxol.Demo.Dashboard,
"Live BEAM dashboard with scheduler, memory, process stats"},
{"showcase", Raxol.Demo.Showcase,
"Interactive component showcase with 5 tabbed sections"}
]
@demo_names Enum.map(@demos, &elem(&1, 0))
@impl Mix.Task
def run(args) do
case OptionParser.parse(args, strict: [list: :boolean]) do
{opts, [], _} ->
if Keyword.get(opts, :list, false) do
print_list()
else
prompt_and_run()
end
{_opts, [name], _} ->
launch(name)
_ ->
print_usage()
end
end
defp launch(name) do
case Enum.find(@demos, fn {n, _, _} -> n == name end) do
{_, module, _} ->
Mix.Task.run("app.start")
Mix.shell().info([:green, "Starting #{name} demo...", :reset])
Mix.shell().info("Press 'q' or Ctrl+C to quit.\n")
{:ok, pid} = Raxol.start_link(module, [])
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :process, ^pid, _reason} -> :ok
end
nil ->
Mix.shell().error("Unknown demo: #{name}")
Mix.shell().error("Available: #{Enum.join(@demo_names, ", ")}")
end
end
defp prompt_and_run do
Mix.shell().info("")
Mix.shell().info([:bright, "Available demos:", :reset])
for {{name, _, desc}, idx} <- Enum.with_index(@demos, 1) do
Mix.shell().info(" #{idx}. #{String.pad_trailing(name, 12)} #{desc}")
end
answer =
Mix.shell().prompt(
"Pick a demo [#{Enum.join(@demo_names, "/")}] (default: counter)"
)
|> String.trim()
|> String.downcase()
name =
case answer do
"" ->
"counter"
n when n in ["1", "2", "3", "4"] ->
Enum.at(@demo_names, String.to_integer(n) - 1)
n when n in @demo_names ->
n
_ ->
Mix.shell().info([:yellow, "Unknown demo, using counter.", :reset])
"counter"
end
launch(name)
end
defp print_list do
Mix.shell().info([:bright, "Available demos:", :reset])
Mix.shell().info("")
for {name, _, desc} <- @demos do
label = String.pad_trailing(name, 12)
Mix.shell().info([" ", :cyan, label, :reset, desc])
end
Mix.shell().info("")
Mix.shell().info("Usage: mix raxol.demo NAME")
end
defp print_usage do
Mix.shell().error("Usage: mix raxol.demo [NAME]")
Mix.shell().error("")
Mix.shell().error("Run without arguments for interactive picker.")
Mix.shell().error("Run with --list to see available demos.")
end
end