Packages

phoenix_kit

1.7.21
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules ai web prompts.html.heex
Raw

lib/modules/ai/web/prompts.html.heex

<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
page_title={@page_title}
current_path={@current_path}
project_title={@project_title}
phoenix_kit_current_scope={@phoenix_kit_current_scope}
current_locale={assigns[:current_locale]}
>
<div class="container flex-col mx-auto px-4 py-6">
<%!-- Header Section --%>
<header class="w-full relative mb-6">
<%!-- Back Button (Left aligned) --%>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin")}
class="btn btn-outline btn-primary btn-sm absolute left-0 top-0 -mb-12"
>
<.icon name="hero-arrow-left" class="w-4 h-4 mr-2" /> Back to Dashboard
</.link>
<%!-- Title Section --%>
<div class="text-center">
<h1 class="text-4xl font-bold text-base-content mb-3">AI Prompts</h1>
<p class="text-lg text-base-content">
Reusable prompt templates with variable substitution
</p>
</div>
</header>
<%!-- Controls --%>
<div class="bg-base-200 rounded-lg p-6 mb-6">
<div class="flex flex-col lg:flex-row gap-4 items-center justify-between">
<%!-- Tabs --%>
<div class="tabs tabs-boxed">
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/endpoints"}
class="tab"
>
<.icon name="hero-server-stack" class="w-4 h-4 mr-2" /> Endpoints
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/prompts"}
class="tab tab-active"
>
<.icon name="hero-document-text" class="w-4 h-4 mr-2" /> Prompts
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/usage"}
class="tab"
>
<.icon name="hero-chart-bar" class="w-4 h-4 mr-2" /> Usage
</.link>
</div>
<%!-- Quick Actions --%>
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/prompts/new"}
class="btn btn-primary"
>
<.icon name="hero-plus" class="w-5 h-5 mr-2" /> New Prompt
</.link>
</div>
</div>
<%!-- Content --%>
<%= if Enum.empty?(@prompts) do %>
<%!-- Empty State --%>
<div class="card bg-base-200 p-8 text-center">
<div class="flex flex-col items-center gap-4">
<.icon name="hero-document-text" class="w-16 h-16 text-base-content/30" />
<h2 class="text-xl font-semibold">No Prompts Yet</h2>
<p class="text-base-content/70 max-w-md">
Create reusable prompt templates with variable substitution.
Use <code class="bg-base-300 px-1 rounded">{"{{VariableName}}"}</code>
syntax for dynamic content.
</p>
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/prompts/new"}
class="btn btn-primary mt-4"
>
<.icon name="hero-plus" class="w-5 h-5 mr-2" /> Create First Prompt
</.link>
</div>
</div>
<% else %>
<%!-- Sort Controls --%>
<div class="flex items-center gap-2 mb-4 flex-wrap">
<span class="text-sm text-base-content/70">Sort by:</span>
<%= for {field, label} <- @sort_options do %>
<button
phx-click="sort"
phx-value-by={field}
class={"btn btn-xs #{if @sort_by == field, do: "btn-primary", else: "btn-ghost"}"}
>
{label}
<%= if @sort_by == field do %>
<.icon
name={if @sort_dir == :asc, do: "hero-chevron-up", else: "hero-chevron-down"}
class="w-3 h-3 ml-1"
/>
<% end %>
</button>
<% end %>
</div>
<%!-- Prompts Grid --%>
<div class="grid gap-4">
<%= for prompt <- @prompts do %>
<div class={"card bg-base-200 #{if !prompt.enabled, do: "opacity-60"}"}>
<div class="card-body p-4">
<div class="flex items-start justify-between">
<div class="flex-1">
<div class="flex items-center gap-3 flex-wrap">
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/prompts/#{prompt.id}/edit"}
class="badge badge-ghost font-mono hover:badge-primary cursor-pointer"
>
#{prompt.id}
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.ai_path() <> "/prompts/#{prompt.id}/edit"}
class="font-semibold text-lg hover:text-primary hover:underline"
>
{prompt.name}
</.link>
<.enabled_badge enabled={prompt.enabled} />
<span class="badge badge-outline font-mono text-xs">{prompt.slug}</span>
</div>
<%!-- Variables --%>
<%= if prompt.variables && length(prompt.variables) > 0 do %>
<div class="mt-2 flex flex-wrap gap-2">
<span class="text-sm text-base-content/70">Variables:</span>
<%= for var <- prompt.variables do %>
<span class="badge badge-sm badge-primary badge-outline font-mono">
{"{{#{var}}}"}
</span>
<% end %>
</div>
<% end %>
<%!-- Content Preview --%>
<div class="mt-2 text-sm text-base-content/70 line-clamp-2">
{PhoenixKit.Modules.AI.Prompt.content_preview(prompt.content)}
</div>
<%!-- Usage Stats --%>
<div class="mt-2 flex flex-wrap gap-4 text-sm">
<div class="flex items-center gap-1 text-base-content/70" title="Usage count">
<.icon name="hero-arrow-path" class="w-4 h-4" />
<span>{prompt.usage_count} uses</span>
</div>
<div class="flex items-center gap-1 text-base-content/70" title="Last used">
<.icon name="hero-clock" class="w-4 h-4" />
<span>
<%= if prompt.last_used_at do %>
<.time_ago datetime={prompt.last_used_at} />
<% else %>
Never used
<% end %>
</span>
</div>
<div class="flex items-center gap-1 text-base-content/70" title="Created">
<.icon name="hero-calendar" class="w-4 h-4" />
<span>
<.time_ago datetime={prompt.inserted_at} />
</span>
</div>
</div>
<%= if prompt.description do %>
<p class="mt-2 text-sm text-base-content/60">{prompt.description}</p>
<% end %>
</div>
<%!-- Actions --%>
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn btn-ghost btn-sm btn-square">
<.icon name="hero-ellipsis-vertical" class="w-5 h-5" />
</div>
<ul
tabindex="0"
class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-48"
>
<li>
<.link navigate={PhoenixKit.Utils.Routes.ai_path() <> "/prompts/#{prompt.id}/edit"}>
<.icon name="hero-pencil" class="w-4 h-4" /> Edit
</.link>
</li>
<li>
<button phx-click="toggle_prompt" phx-value-id={prompt.id}>
<.icon
name={if prompt.enabled, do: "hero-pause", else: "hero-play"}
class="w-4 h-4"
/>
{if prompt.enabled, do: "Disable", else: "Enable"}
</button>
</li>
<li class="divider"></li>
<li>
<button
phx-click="delete_prompt"
phx-value-id={prompt.id}
data-confirm="Are you sure you want to delete this prompt?"
class="text-error"
>
<.icon name="hero-trash" class="w-4 h-4" /> Delete
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
<% end %>
</div>
<%!-- Pagination --%>
<% total_pages = ceil(@total_prompts / @page_size) %>
<%= if total_pages > 1 do %>
<div class="flex justify-center p-4 border-t border-base-300">
<div class="join">
<%= for page_num <- 1..total_pages do %>
<button
class={"join-item btn btn-sm #{if page_num == @page, do: "btn-active", else: ""}"}
phx-click="goto_page"
phx-value-page={page_num}
>
{page_num}
</button>
<% end %>
</div>
</div>
<% end %>
<% end %>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>