149 lines
11 KiB
Django/Jinja
149 lines
11 KiB
Django/Jinja
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{{ title }}</title>
|
|
<meta name="description" content="{{ description }}">
|
|
<link rel="stylesheet" href="/static/css/style.css">
|
|
</head>
|
|
<body class="bg-white text-gray-900 antialiased flex flex-col min-h-screen">
|
|
{% if user is defined and user %}
|
|
{# ── Authenticated nav ─────────────────────────────────────── #}
|
|
<nav class="border-b border-gray-200 pt-3">
|
|
{# Top bar: breadcrumb + user actions #}
|
|
<div class="max-w-6xl mx-auto px-4 pb-3 flex items-center justify-between">
|
|
<div class="flex items-center gap-2 text-sm min-w-0">
|
|
<a href="/dashboard" class="text-lg font-bold tracking-tight shrink-0">forage</a>
|
|
{% if current_org is defined and current_org %}
|
|
<span class="text-gray-300">/</span>
|
|
{% if orgs is defined and orgs | length > 1 %}
|
|
<details class="relative">
|
|
<summary class="font-medium text-gray-900 hover:text-black cursor-pointer list-none">
|
|
{{ current_org }}
|
|
<svg class="inline w-3 h-3 ml-0.5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
|
|
</summary>
|
|
<div class="absolute left-0 mt-1 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-20 py-1">
|
|
{% for org in orgs %}
|
|
<a href="/orgs/{{ org.name }}/projects" class="block px-3 py-1.5 text-sm hover:bg-gray-50{% if org.name == current_org %} font-medium bg-gray-50{% endif %}">{{ org.name }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
</details>
|
|
{% else %}
|
|
<a href="/orgs/{{ current_org }}/projects" class="font-medium text-gray-900 hover:text-black">{{ current_org }}</a>
|
|
{% endif %}
|
|
{% if projects is defined and projects | length > 0 %}
|
|
<span class="text-gray-300">/</span>
|
|
<details class="relative">
|
|
<summary class="font-medium text-gray-900 hover:text-black cursor-pointer list-none truncate">
|
|
{% if project_name is defined and project_name %}{{ project_name }}{% else %}Select project{% endif %}
|
|
<svg class="inline w-3 h-3 ml-0.5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
|
|
</summary>
|
|
<div class="absolute left-0 mt-1 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-20 py-1">
|
|
{% for p in projects %}
|
|
<a href="/orgs/{{ current_org }}/projects/{{ p }}" class="block px-3 py-1.5 text-sm hover:bg-gray-50{% if project_name is defined and p == project_name %} font-medium bg-gray-50{% endif %}">{{ p }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
</details>
|
|
{% elif project_name is defined and project_name %}
|
|
<span class="text-gray-300">/</span>
|
|
<a href="/orgs/{{ current_org }}/projects/{{ project_name }}" class="font-medium text-gray-900 hover:text-black truncate">{{ project_name }}</a>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
<div class="flex items-center gap-3 shrink-0">
|
|
<a href="/notifications" class="text-gray-400 hover:text-gray-900 relative" title="Notifications">
|
|
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
|
|
</svg>
|
|
</a>
|
|
<a href="/settings/account" class="text-sm text-gray-500 hover:text-gray-900">{{ user.username }}</a>
|
|
<form method="POST" action="/logout" class="inline">
|
|
<input type="hidden" name="_csrf" value="{{ csrf_token }}">
|
|
<button type="submit" class="text-sm text-gray-500 hover:text-gray-900">Sign out</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{# Tab navigation #}
|
|
<div class="max-w-6xl mx-auto px-4 mt-2">
|
|
<div class="flex gap-1 -mb-px overflow-x-auto">
|
|
{% if project_name is defined and project_name %}
|
|
{# ── Project-level tabs ─────────────────────────────── #}
|
|
<a href="/orgs/{{ current_org }}/projects/{{ project_name }}" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'project_overview' %} text-gray-900 border-gray-900{% endif %}">Overview</a>
|
|
<a href="/orgs/{{ current_org }}/projects/{{ project_name }}/releases" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'project_releases' %} text-gray-900 border-gray-900{% endif %}">Releases</a>
|
|
{% elif current_org is defined and current_org %}
|
|
{# ── Org-level tabs ─────────────────────────────────── #}
|
|
<a href="/dashboard" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'dashboard' %} text-gray-900 border-gray-900{% endif %}">Overview</a>
|
|
<a href="/orgs/{{ current_org }}/projects" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'projects' %} text-gray-900 border-gray-900{% endif %}">Projects</a>
|
|
<a href="/orgs/{{ current_org }}/settings/members" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'members' %} text-gray-900 border-gray-900{% endif %}">Members</a>
|
|
<a href="/orgs/{{ current_org }}/destinations" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'destinations' %} text-gray-900 border-gray-900{% endif %}">Destinations</a>
|
|
<a href="/orgs/{{ current_org }}/usage" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'usage' %} text-gray-900 border-gray-900{% endif %}">Usage</a>
|
|
<a href="/settings/tokens" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'tokens' %} text-gray-900 border-gray-900{% endif %}">Tokens</a>
|
|
<a href="/settings/account" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'account' %} text-gray-900 border-gray-900{% endif %}">Settings</a>
|
|
{% else %}
|
|
{# ── Global tabs (no org context) ───────────────────── #}
|
|
<a href="/dashboard" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'dashboard' %} text-gray-900 border-gray-900{% endif %}">Overview</a>
|
|
<a href="/settings/tokens" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'tokens' %} text-gray-900 border-gray-900{% endif %}">Tokens</a>
|
|
<a href="/settings/account" class="px-3 py-2 text-sm text-gray-500 hover:text-gray-900 border-b-2 border-transparent hover:border-gray-300{% if active_tab is defined and active_tab == 'account' %} text-gray-900 border-gray-900{% endif %}">Settings</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
{% else %}
|
|
{# ── Marketing nav ─────────────────────────────────────────── #}
|
|
<nav class="border-b border-gray-200">
|
|
<div class="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
|
|
<a href="/" class="text-xl font-bold tracking-tight">forage</a>
|
|
<div class="flex items-center gap-6">
|
|
<a href="/pricing" class="text-sm text-gray-600 hover:text-gray-900">Pricing</a>
|
|
<a href="/components" class="text-sm text-gray-600 hover:text-gray-900">Components</a>
|
|
<a href="/login" class="text-sm font-medium px-4 py-2 bg-gray-900 text-white rounded-md hover:bg-gray-800">Sign in</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
{% endif %}
|
|
|
|
<main class="flex-1">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<footer class="border-t border-gray-200 mt-auto pt-0">
|
|
<div class="max-w-6xl mx-auto px-4 py-12">
|
|
<div class="grid grid-cols-2 md:grid-cols-3 gap-8">
|
|
<div>
|
|
<h3 class="font-bold text-sm mb-3">Product</h3>
|
|
<ul class="space-y-2 text-sm text-gray-600">
|
|
<li><a href="/pricing" class="hover:text-gray-900">Pricing</a></li>
|
|
<li><a href="/components" class="hover:text-gray-900">Components</a></li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-bold text-sm mb-3">Platform</h3>
|
|
<ul class="space-y-2 text-sm text-gray-600">
|
|
<li><a href="/signup" class="hover:text-gray-900">Get Started</a></li>
|
|
<li><a href="/login" class="hover:text-gray-900">Sign In</a></li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-bold text-sm mb-3">Forest</h3>
|
|
<ul class="space-y-2 text-sm text-gray-600">
|
|
<li><a href="https://src.rawpotion.io/rawpotion/forest" class="hover:text-gray-900">Forest on Git</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="mt-12 pt-8 border-t border-gray-200 text-sm text-gray-500">
|
|
© 2026 Forage. Built with Forest.
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
<script>
|
|
document.querySelectorAll('time[datetime]').forEach(function(el) {
|
|
try {
|
|
var d = new Date(el.getAttribute('datetime'));
|
|
if (!isNaN(d)) el.title = d.toLocaleString();
|
|
} catch(e) {}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|