Files
Claper/lib/claper_web/templates/layout/admin.html.heex
2025-11-20 10:44:06 +01:00

317 lines
12 KiB
Plaintext

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{csrf_meta_tag()}
<.live_title suffix=" · Claper Admin">
{assigns[:page_title] || "Admin Dashboard"}
</.live_title>
<link phx-track-static rel="stylesheet" href="/assets/app.css" />
<link phx-track-static rel="stylesheet" href="/assets/admin.css" />
<link rel="icon" type="image/png" href="/images/favicon.png" />
<script defer phx-track-static type="text/javascript" src="/assets/app.js">
</script>
</head>
<body>
<div class="drawer lg:drawer-open">
<input id="drawer-toggle" type="checkbox" class="drawer-toggle" />
<div class="drawer-content flex flex-col">
<!-- Navbar for mobile -->
<div class="navbar lg:hidden bg-base-100 shadow-lg">
<div class="flex-none">
<label for="drawer-toggle" class="btn btn-square btn-ghost drawer-button">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="inline-block w-5 h-5 stroke-current"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
>
</path>
</svg>
</label>
</div>
<div class="flex-1">
<a href={~p"/admin"} class="btn btn-ghost normal-case text-xl">
<img src="/images/logo.svg" class="h-24 mr-2" /> {gettext("Admin")}
</a>
</div>
</div>
<!-- Page content -->
<main class="flex-1 overflow-y-auto bg-base-200 p-4 lg:p-8">
<!-- Toast container for flash messages -->
<div class="toast toast-top toast-end" id="flash-messages">
<%= if Phoenix.Flash.get(@flash, :info) do %>
<div class="alert alert-info shadow-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="stroke-current shrink-0 w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
>
</path>
</svg>
<span>{Phoenix.Flash.get(@flash, :info)}</span>
<button class="btn btn-ghost btn-xs" onclick="this.parentElement.remove()">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<% end %>
<%= if Phoenix.Flash.get(@flash, :success) do %>
<div class="alert alert-success shadow-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>{Phoenix.Flash.get(@flash, :success)}</span>
<button class="btn btn-ghost btn-xs" onclick="this.parentElement.remove()">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<% end %>
<%= if Phoenix.Flash.get(@flash, :warning) do %>
<div class="alert alert-warning shadow-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
<span>{Phoenix.Flash.get(@flash, :warning)}</span>
<button class="btn btn-ghost btn-xs" onclick="this.parentElement.remove()">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<% end %>
<%= if Phoenix.Flash.get(@flash, :error) do %>
<div class="alert alert-error shadow-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>{Phoenix.Flash.get(@flash, :error)}</span>
<button class="btn btn-ghost btn-xs" onclick="this.parentElement.remove()">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<% end %>
</div>
<div class="p-8 md:p-16">
{@inner_content}
</div>
</main>
</div>
<!-- Sidebar -->
<div class="drawer-side">
<label for="drawer-toggle" class="drawer-overlay"></label>
<aside class="bg-base-100 min-h-full px-12">
<div class="flex items-center p-5 gap-x-3">
<img src="/images/logo.svg" class="h-24" />
<h1 class="text-xl font-bold !font-display">{gettext("Admin")}</h1>
</div>
<ul class="menu">
<li>
<.link
patch={~p"/admin"}
class={"#{if @conn.path_info == ["admin"], do: "active", else: ""}"}
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
/>
</svg>
{gettext("Dashboard")}
</.link>
</li>
<li>
<.link
patch={~p"/admin/events"}
class={"#{if @conn.path_info == ["admin", "events"], do: "active", else: ""}"}
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
/>
</svg>
{gettext("Events")}
</.link>
</li>
<li>
<.link
patch={~p"/admin/users"}
class={"#{if @conn.path_info == ["admin", "users"], do: "active", else: ""}"}
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
/>
</svg>
{gettext("Users")}
</.link>
</li>
<%!-- <li>
<.link
patch={~p"/admin/oidc_providers"}
class={"#{if @conn.path_info == ["admin", "oidc_providers"], do: "active", else: ""}"}
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
/>
</svg>
{gettext("OIDC Providers")}
</.link>
</li> --%>
<div class="divider"></div>
<li>
<a href="https://docs.claper.co" target="_blank" rel="noopener noreferrer">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
/>
</svg>
{gettext("Documentation")}
<svg class="w-3 h-3 ml-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
</svg>
</a>
</li>
<div class="mt-auto pt-4">
<li>
<a href={~p"/events"} class="btn btn-outline btn-sm">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 19l-7-7m0 0l7-7m-7 7h18"
/>
</svg>
{gettext("Back to app")}
</a>
</li>
</div>
</ul>
</aside>
</div>
</div>
<!-- Auto-dismiss flash messages script -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Auto-dismiss flash messages after 5 seconds
const flashMessages = document.querySelectorAll('#flash-messages .alert');
if (flashMessages.length > 0) {
setTimeout(function() {
flashMessages.forEach(function(message) {
if (document.body.contains(message)) {
message.style.transition = 'opacity 0.5s ease';
message.style.opacity = '0';
setTimeout(function() {
message.remove();
}, 500);
}
});
}, 5000);
}
});
</script>
</body>
</html>