towerops/lib/towerops_web/controllers/user_registration_html/new.html.heex
Graham McIntire 5a7cdc7138 refactor: apply custom color palette across entire codebase
- Replace gray->cool-steel, blue/indigo->cerulean, red->sweet-salmon, yellow/amber->wheat
- Dark sidebar: sidebar/footer use cool-steel-800 bg, text lightened for contrast
- ~11,600 color replacements across ~99 files
- Update tests for new color class names
2026-06-23 10:58:48 -05:00

218 lines
9.1 KiB
Text

<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="mx-auto max-w-4xl">
<div class="overflow-hidden rounded-2xl bg-white shadow-xl dark:bg-cool-steel-900 lg:grid lg:grid-cols-5">
<!-- Left: Brand panel -->
<div class="hidden lg:col-span-2 lg:flex lg:flex-col lg:justify-between bg-gradient-to-br from-cerulean-600 via-cerulean-700 to-cerulean-800 p-8 text-white">
<div>
<div class="flex items-center gap-2">
<.icon name="hero-signal" class="size-8" />
<span class="text-xl font-bold">TowerOps</span>
</div>
<p class="mt-6 text-lg font-medium leading-relaxed text-cerulean-100">
{t("Start monitoring your network in minutes.")}
</p>
</div>
<div class="mt-auto space-y-4">
<div class="rounded-lg bg-white/10 p-4 backdrop-blur-sm">
<p class="text-sm font-semibold text-white">{t("Free tier includes:")}</p>
<ul class="mt-2 space-y-1.5 text-sm text-cerulean-100">
<li class="flex items-center gap-2">
<.icon name="hero-check" class="size-4 text-green-300" />
{t("Monitor up to 10 devices")}
</li>
<li class="flex items-center gap-2">
<.icon name="hero-check" class="size-4 text-green-300" />
{t("Real-time alerts")}
</li>
<li class="flex items-center gap-2">
<.icon name="hero-check" class="size-4 text-green-300" />
{t("Performance charts & history")}
</li>
<li class="flex items-center gap-2">
<.icon name="hero-check" class="size-4 text-green-300" />
{t("No credit card required")}
</li>
</ul>
</div>
</div>
</div>
<!-- Right: Registration form -->
<div class="col-span-3 px-6 py-10 sm:px-12">
<!-- Mobile brand mark -->
<div class="mb-6 flex items-center justify-center gap-2 lg:hidden">
<.icon name="hero-signal" class="size-7 text-cerulean-600 dark:text-cerulean-400" />
<span class="text-lg font-bold text-cool-steel-900 dark:text-white">TowerOps</span>
</div>
<div class="text-center lg:text-left">
<h1 class="text-2xl font-bold text-cool-steel-900 dark:text-white">
<%= if @invitation do %>
{t_auth("Join %{organization}", organization: @invitation.organization.name)}
<% else %>
{t_auth("Create your account")}
<% end %>
</h1>
<p class="mt-2 text-sm text-cool-steel-600 dark:text-cool-steel-400">
{t_auth("Already registered?")}
<.link
navigate={~p"/users/log-in"}
class="font-semibold text-cerulean-600 hover:text-cerulean-700 dark:text-cerulean-400 dark:hover:text-cerulean-300"
>
{t_auth("Log in")}
</.link>
</p>
</div>
<!-- Mobile: value prop banner -->
<%= unless @invitation do %>
<div class="mt-5 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-2.5 text-sm text-green-800 dark:bg-green-900/20 dark:text-green-300 lg:hidden">
<.icon name="hero-gift" class="size-5 flex-shrink-0" />
<span class="font-medium">
{t_auth("First 10 devices free — no credit card needed")}
</span>
</div>
<% end %>
<%= if @invitation do %>
<div class="mt-5 rounded-lg bg-cerulean-50 dark:bg-cerulean-900/20 p-4 border border-cerulean-200 dark:border-cerulean-800">
<p class="text-sm text-cerulean-900 dark:text-cerulean-100">
{t_auth("You've been invited to join %{organization} as a %{role}.",
organization: @invitation.organization.name,
role: @invitation.role
)}
</p>
</div>
<% end %>
<div class="mt-8">
<.form :let={f} for={@form} action={~p"/users/register"}>
<%= if @invitation_token do %>
<input type="hidden" name="user[invitation_token]" value={@invitation_token} />
<% end %>
<.input
field={f[:email]}
type="email"
label={t_auth("Email")}
autocomplete="email"
required
phx-mounted={JS.focus()}
/>
<.input
field={f[:password]}
type="password"
label={t_auth("Password")}
autocomplete="new-password"
required
/>
<!-- Password strength indicator (CSS-only) -->
<div class="mb-4 -mt-2">
<div class="flex gap-1">
<div
class="h-1 flex-1 rounded-full bg-cool-steel-200 dark:bg-cool-steel-700 password-strength-bar"
data-index="1"
>
</div>
<div
class="h-1 flex-1 rounded-full bg-cool-steel-200 dark:bg-cool-steel-700 password-strength-bar"
data-index="2"
>
</div>
<div
class="h-1 flex-1 rounded-full bg-cool-steel-200 dark:bg-cool-steel-700 password-strength-bar"
data-index="3"
>
</div>
<div
class="h-1 flex-1 rounded-full bg-cool-steel-200 dark:bg-cool-steel-700 password-strength-bar"
data-index="4"
>
</div>
</div>
<p class="mt-1 text-xs text-cool-steel-500 dark:text-cool-steel-500">
{t_auth("Use 12+ characters for a strong password")}
</p>
</div>
<%= unless @invitation do %>
<.input
name="user[organization_name]"
value=""
type="text"
label={t_auth("Organization Name")}
placeholder={t_auth("My Company")}
required
/>
<% end %>
<div class="space-y-3 mt-6">
<div class="flex items-start">
<div class="flex items-center h-5">
<input
id="privacy_policy_consent"
name="user[privacy_policy_consent]"
type="checkbox"
required
class="h-4 w-4 rounded border-cool-steel-300 text-cerulean-600 focus:ring-cerulean-500 dark:border-cool-steel-600 dark:bg-cool-steel-800 dark:checked:bg-cerulean-500 dark:checked:border-cerulean-500"
/>
</div>
<div class="ml-3 text-sm">
<label
for="privacy_policy_consent"
class="text-cool-steel-700 dark:text-cool-steel-300"
>
{t_auth("I agree to the %{link}",
link:
raw(
~s(<a href="/privacy" target="_blank" class="font-medium text-cerulean-600 hover:text-cerulean-700 dark:text-cerulean-400 dark:hover:text-cerulean-300">#{t_auth("Privacy Policy")}</a>)
)
)}
<span class="text-sweet-salmon-600 dark:text-sweet-salmon-400">*</span>
</label>
</div>
</div>
<div class="flex items-start">
<div class="flex items-center h-5">
<input
id="terms_of_service_consent"
name="user[terms_of_service_consent]"
type="checkbox"
required
class="h-4 w-4 rounded border-cool-steel-300 text-cerulean-600 focus:ring-cerulean-500 dark:border-cool-steel-600 dark:bg-cool-steel-800 dark:checked:bg-cerulean-500 dark:checked:border-cerulean-500"
/>
</div>
<div class="ml-3 text-sm">
<label
for="terms_of_service_consent"
class="text-cool-steel-700 dark:text-cool-steel-300"
>
{t_auth("I agree to the %{link}",
link:
raw(
~s(<a href="/terms" target="_blank" class="font-medium text-cerulean-600 hover:text-cerulean-700 dark:text-cerulean-400 dark:hover:text-cerulean-300">#{t_auth("Terms of Service")}</a>)
)
)}
<span class="text-sweet-salmon-600 dark:text-sweet-salmon-400">*</span>
</label>
</div>
</div>
</div>
<.button
phx-disable-with={t_auth("Creating account...")}
class="w-full mt-6"
variant="primary"
>
{if @invitation,
do: t_auth("Accept invitation and create account"),
else: t_auth("Create an account")}
<span aria-hidden="true">→</span>
</.button>
</.form>
</div>
</div>
</div>
</div>
</Layouts.app>