- Fixed debounce_ms/0 function still using Mix.env() - Changed to Application.get_env(:towerops, :env) - This was causing crashes in staging/production
166 lines
6.3 KiB
Text
166 lines
6.3 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-gray-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-blue-600 via-blue-700 to-indigo-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-blue-100">
|
|
{t("Monitor your entire network from a single dashboard.")}
|
|
</p>
|
|
</div>
|
|
<div class="mt-auto">
|
|
<div class="rounded-lg bg-white/10 p-4 backdrop-blur-sm">
|
|
<p class="text-sm italic text-blue-100">
|
|
{t(
|
|
"\"TowerOps cut our response time to network issues by 80%. We can see problems before customers even notice.\""
|
|
)}
|
|
</p>
|
|
<p class="mt-3 text-xs font-semibold text-blue-200">{t("— WISP Network Operator")}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right: Login 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-blue-600 dark:text-blue-400" />
|
|
<span class="text-lg font-bold text-gray-900 dark:text-white">TowerOps</span>
|
|
</div>
|
|
|
|
<div class="text-center lg:text-left">
|
|
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
|
|
{t_auth("Log in")}
|
|
</h1>
|
|
<%= if @current_scope do %>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
|
{t_auth("You need to reauthenticate to perform sensitive actions on your account.")}
|
|
</p>
|
|
<% else %>
|
|
<div class="mt-4">
|
|
<.link navigate={~p"/users/register"}>
|
|
<.button class="w-full" variant="secondary">
|
|
{t_auth("Create an account")} <span aria-hidden="true">→</span>
|
|
</.button>
|
|
</.link>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div
|
|
:if={local_mail_adapter?()}
|
|
class="mt-5 rounded-lg bg-blue-50 p-4 dark:bg-blue-950"
|
|
>
|
|
<div class="flex">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-6 w-6 flex-shrink-0 text-blue-600 dark:text-blue-400"
|
|
/>
|
|
<div class="ml-3">
|
|
<p class="text-sm text-blue-700 dark:text-blue-200">
|
|
{t_auth("You are running the local mail adapter.")}
|
|
</p>
|
|
<p class="mt-1 text-sm text-blue-700 dark:text-blue-200">
|
|
{t_auth("To see sent emails, visit")}
|
|
<a href="/dev/mailbox" class="font-medium underline">{t_auth("the mailbox page")}</a>.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 space-y-6">
|
|
<!-- Password Login -->
|
|
<.form
|
|
:let={f}
|
|
for={@form}
|
|
as={:user}
|
|
id="login_form_password"
|
|
action={~p"/users/log-in"}
|
|
>
|
|
<.input
|
|
readonly={!!@current_scope}
|
|
field={f[:email]}
|
|
id="user_email_password"
|
|
type="email"
|
|
label={t_auth("Email")}
|
|
autocomplete="email"
|
|
required
|
|
phx-mounted={JS.focus()}
|
|
/>
|
|
<.input
|
|
field={f[:password]}
|
|
id="user_password"
|
|
type="password"
|
|
label={t_auth("Password")}
|
|
autocomplete="current-password"
|
|
required
|
|
/>
|
|
<div class="flex items-center justify-between">
|
|
<label class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
|
|
<input
|
|
type="checkbox"
|
|
name={@form[:remember_me].name}
|
|
value="true"
|
|
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800"
|
|
/>
|
|
{t_auth("Remember me")}
|
|
</label>
|
|
<.link
|
|
navigate={~p"/users/reset-password"}
|
|
class="text-sm font-semibold text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
|
>
|
|
{t_auth("Forgot password?")}
|
|
</.link>
|
|
</div>
|
|
<div class="mt-4">
|
|
<.button class="w-full" variant="primary">
|
|
{t_auth("Log in")} <span aria-hidden="true">→</span>
|
|
</.button>
|
|
</div>
|
|
</.form>
|
|
|
|
<div class="relative">
|
|
<div class="absolute inset-0 flex items-center">
|
|
<div class="w-full border-t border-gray-200 dark:border-white/10"></div>
|
|
</div>
|
|
<div class="relative flex justify-center text-sm">
|
|
<span class="bg-white px-3 text-gray-500 dark:bg-gray-900 dark:text-gray-500">
|
|
{t("or")}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Magic Link -->
|
|
<.form :let={f} for={@form} as={:user} id="login_form_magic" action={~p"/users/log-in"}>
|
|
<.input
|
|
readonly={!!@current_scope}
|
|
field={f[:email]}
|
|
id="user_email_magic"
|
|
type="email"
|
|
label={t_auth("Email")}
|
|
autocomplete="email"
|
|
required
|
|
/>
|
|
<.button class="w-full" variant="secondary">
|
|
<.icon name="hero-envelope" class="size-4" />
|
|
{t_auth("Send me a login link instead")}
|
|
</.button>
|
|
</.form>
|
|
|
|
<p class="text-center text-sm text-gray-500 dark:text-gray-500">
|
|
<.link
|
|
href={~p"/users/confirm"}
|
|
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 hover:underline"
|
|
>
|
|
{t_auth("Didn't receive confirmation instructions?")}
|
|
</.link>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Layouts.app>
|