Begin redesign
This commit is contained in:
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>{% block title %}Sshecret Admin{% endblock %}</title>
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{% include 'base/partials/stylesheets.html.j2' %}
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-50 text-gray-900 min-h-screen flex flex-col">
|
||||||
|
|
||||||
|
<!-- Optional: Shoelace modals, toasts -->
|
||||||
|
<sl-alert id="global-alert" variant="primary" duration="4000" closable></sl-alert>
|
||||||
|
<sl-dialog id="global-dialog" label="Dialog"></sl-dialog>
|
||||||
|
|
||||||
|
<!-- Layout Container -->
|
||||||
|
<div class="flex flex-1 h-full overflow-hidden">
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
|
||||||
|
<aside class="hidden md:flex md:w-64 flex-col h-full min-h-screen bg-white border-r border-gray-300" id="sidebar" aria-label="sidebar">
|
||||||
|
{% include "base/partials/sidebar.html.j2" %}
|
||||||
|
</aside>
|
||||||
|
<!-- Main Panel -->
|
||||||
|
<div class="flex-1 flex flex-col overflow-hidden">
|
||||||
|
|
||||||
|
<!-- Topbar -->
|
||||||
|
<header class="bg-white border-b px-4 py-3 border-gray-300">
|
||||||
|
{% include "base/partials/navbar.html.j2" %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Main Content Area -->
|
||||||
|
<main id="content" class="flex-1 overflow-y-auto" hx-target="this" hx-swap="innerHTML">
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
{% endblock %}
|
||||||
|
<div class="p-4" id="maincontent">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% include 'base/partials/scripts.html.j2' %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
{% extends "/base/base.html.j2" %}
|
||||||
|
|
||||||
|
{% block title %}{{ title or "Page" }}{% endblock %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
|
||||||
|
<div class="p-4 bg-white block sm:flex items-center justify-between border-b border-gray-200">
|
||||||
|
<nav class="text-sm text-gray-500" aria-label="Breadcrumb">
|
||||||
|
|
||||||
|
<sl-breadcrumb>
|
||||||
|
<sl-breadcrumb-item>
|
||||||
|
<sl-icon slot="prefix" name="house"></sl-icon>
|
||||||
|
<a href="/">Home</a>
|
||||||
|
</sl-breadcrumb-item>
|
||||||
|
{% if breadcrumbs %}
|
||||||
|
{% for label, url in breadcrumbs %}
|
||||||
|
<sl-breadcrumb-item>
|
||||||
|
{% if url %}
|
||||||
|
<a href="{{url}}">{{label}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ label }}
|
||||||
|
{% endif %}
|
||||||
|
</sl-breadcrumb-item>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</sl-breadcrumb>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<!-- Breadcrumbs -->
|
||||||
|
|
||||||
|
<!-- Page Content -->
|
||||||
|
<section>
|
||||||
|
{% block page_content %}
|
||||||
|
<p>This is a generic page.</p>
|
||||||
|
{% endblock %}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
<header class="flex items-center justify-between">
|
||||||
|
|
||||||
|
<!-- Left: Sidebar toggle (for mobile) + Title -->
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
|
||||||
|
<!-- Mobile sidebar toggle -->
|
||||||
|
<button
|
||||||
|
id="sidebar-toggle"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-controls="mobile-sidebar"
|
||||||
|
class="md:hidden text-gray-600 hover:text-gray-900 focus:outline-none"
|
||||||
|
aria-label="Toggle sidebar"
|
||||||
|
>
|
||||||
|
<sl-icon name="list" class="text-xl"></sl-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Page title or logo -->
|
||||||
|
<a href="/" class="flex ml-2 md:mr-24">
|
||||||
|
<img
|
||||||
|
src="{{ url_for('static', path='logo.svg') }}"
|
||||||
|
class="h-11 mr-3"
|
||||||
|
alt="Sshecret Logo"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="self-center text-xl font-semibold sm:text-2xl whitespace-nowrap dark:text-white"
|
||||||
|
>Sshecret</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: User menu -->
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
||||||
|
id="user-menu-button-2"
|
||||||
|
aria-expanded="false"
|
||||||
|
data-dropdown-toggle="dropdown-2"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Open user menu</span>
|
||||||
|
<sl-avatar label="User avatar"></sl-avatar>
|
||||||
|
</button>
|
||||||
|
<!-- Dropdown placeholder -->
|
||||||
|
<div
|
||||||
|
class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600"
|
||||||
|
id="dropdown-2"
|
||||||
|
>
|
||||||
|
<div class="px-4 py-3" role="none">
|
||||||
|
<p class="text-sm text-gray-900 dark:text-white" role="none">
|
||||||
|
{{ user.display_name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ul class="py-1" role="none">
|
||||||
|
{% if user.local %}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="/password"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem"
|
||||||
|
>Change Password</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="/logout"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem"
|
||||||
|
>Logout</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<!-- You can later replace this with a Flowbite dropdown or Shoelace menu -->
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
{# <script src="{{ url_for('static', path='js/sidebar.js') }}"></script> #}
|
||||||
|
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@9.0.3"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||||
|
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.20.1/cdn/shoelace-autoloader.js"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', path="js/prism.js") }}"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const sidebarToggle = document.getElementById('sidebar-toggle');
|
||||||
|
const sidebarDrawer = document.getElementById('sidebar');
|
||||||
|
|
||||||
|
sidebarToggle?.addEventListener('click', () => {
|
||||||
|
sidebarDrawer.classList.toggle("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.addEventListener("htmx:afterSwap", (e) => {
|
||||||
|
const swappedEl = e.target;
|
||||||
|
|
||||||
|
const initTargets = swappedEl.querySelectorAll(".flowbite-init-target");
|
||||||
|
if (initTargets.length > 0 && typeof window.initFlowbite === "function") {
|
||||||
|
window.initFlowbite();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
<!-- Sidebar Container -->
|
||||||
|
|
||||||
|
<!-- Top: Brand -->
|
||||||
|
<div class="px-4 py-6">
|
||||||
|
|
||||||
|
<a href="/" class="text-xl font-semibold text-gray-800">
|
||||||
|
🐚 Sshecret
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="flex-1 overflow-y-auto px-4" aria-label="navigation">
|
||||||
|
<ul class="space-y-">
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/" class="flex items-center px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100">
|
||||||
|
<sl-icon name="house"></sl-icon>
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/clients/" class="flex items-center px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100">
|
||||||
|
<sl-icon name="person-fill-lock"> </sl-icon>
|
||||||
|
Clients
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/admin/secrets" class="flex items-center px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100">
|
||||||
|
<sl-icon name="database-lock"></sl-icon>
|
||||||
|
Secrets
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/admin/audit" class="flex items-center px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100">
|
||||||
|
<sl-icon name="card-list"></sl-icon>
|
||||||
|
Audit Log
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', path='css/main.css') }}"
|
||||||
|
type="text/css"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', path='css/prism.css') }}"
|
||||||
|
type="text/css"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', path='css/style.css') }}"
|
||||||
|
type="text/css"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<link
|
||||||
|
href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
media="(prefers-color-scheme:light)"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.20.1/cdn/themes/light.css"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
media="(prefers-color-scheme:dark)"
|
||||||
|
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.20.1/cdn/themes/dark.css"
|
||||||
|
onload="document.documentElement.classList.add('sl-theme-dark');"
|
||||||
|
/>
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
{% extends 'base/page.html.j2' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Clients{% endblock %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
|
||||||
|
<!-- Master-Detail Layout -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-[300px_1fr] gap-4">
|
||||||
|
|
||||||
|
<!-- Master (e.g., tree or list) -->
|
||||||
|
<div id="master-pane">
|
||||||
|
{% block master %}
|
||||||
|
<p>Master list goes here</p>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detail (loaded by HTMX or inline) -->
|
||||||
|
<div id="detail-pane" class="bg-white rounded shadow p-4">
|
||||||
|
{% block detail %}
|
||||||
|
<p>Select an item from the list to view details.</p>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
{% extends "/dashboard/_base.html" %} {% block content %}
|
{% extends "/base/base.html.j2" %} {% block content %}
|
||||||
|
|
||||||
<div class="px-4 pt-6">
|
<div class="px-4 pt-6">
|
||||||
<div class="py-8 px-4 mt-4 mx-auto max-w-screen-xl text-center lg:py-16">
|
<div class="py-8 px-4 mt-4 mx-auto max-w-screen-xl text-center lg:py-16">
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="main-content" class="relative w-full h-full overflow-y-auto bg-gray-50 lg:ml-64 dark:bg-gray-900 flex flex-col md:flex-row flex-grow">
|
<div id="main-content" class="relative w-full h-full overflow-y-auto bg-gray-50 lg:ml-64 dark:bg-gray-900 flex flex-col md:flex-row flex-grow">
|
||||||
<main class="flex-grow p-4 order-2 md:order-1">
|
<main>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@ -107,6 +107,37 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.get("/clients/new/")
|
||||||
|
async def get_new_client_tree(
|
||||||
|
request: Request,
|
||||||
|
current_user: Annotated[LocalUserInfo, Depends(dependencies.get_user_info)],
|
||||||
|
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
|
||||||
|
) -> Response:
|
||||||
|
"""Get client tree view."""
|
||||||
|
page = 1
|
||||||
|
per_page = CLIENTS_PER_PAGE
|
||||||
|
offset = 0
|
||||||
|
|
||||||
|
client_filter = ClientFilter(offset=offset, limit=per_page)
|
||||||
|
results = await admin.query_clients(client_filter)
|
||||||
|
paginate = PagingInfo(
|
||||||
|
page=page, limit=per_page, total=results.total_results, offset=offset
|
||||||
|
)
|
||||||
|
|
||||||
|
LOG.info("Results %r", results)
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
request,
|
||||||
|
"clients/redesign.html.j2",
|
||||||
|
{
|
||||||
|
"page_title": "Clients",
|
||||||
|
"offset": offset,
|
||||||
|
"pages": paginate,
|
||||||
|
"clients": results.clients,
|
||||||
|
"user": current_user,
|
||||||
|
"results": results,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@app.get("/clients/page/{page}")
|
@app.get("/clients/page/{page}")
|
||||||
async def get_client_page(
|
async def get_client_page(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@ -2854,6 +2854,11 @@
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:w-64 {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
width: calc(var(--spacing) * 64);
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:w-\[calc\(100\%-256px\)\] {
|
.md\:w-\[calc\(100\%-256px\)\] {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
width: calc(100% - 256px);
|
width: calc(100% - 256px);
|
||||||
@ -2879,6 +2884,11 @@
|
|||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:grid-cols-\[300px_1fr\] {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
grid-template-columns: 300px 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:flex-row {
|
.md\:flex-row {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|||||||
Reference in New Issue
Block a user