This is an automated email from the ASF dual-hosted git repository.

wave pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


The following commit(s) were added to refs/heads/main by this push:
     new 4605c0e  New top nav menus (#393)
4605c0e is described below

commit 4605c0e001c8327d102899153d6ffd1a12a326e7
Author: Dave Fisher <[email protected]>
AuthorDate: Mon Dec 8 12:28:50 2025 -0800

    New top nav menus (#393)
    
    * New top nav menus
    
    * Hamburger drop down
    
    * Responsive point for top nav hamburger
    
    * Cleanup head data whitespace #372
    
    * Revert "Cleanup head data whitespace #372"
    
    This reverts commit ebc396f1ee60aacb0ea86a4c4f43717df36cc0dd.
    
    * Proper jinja block use
    
    * Recheck playwright error
    
    * Test without sidebar
    
    * Click topnav button
    
    * Revert "Recheck playwright error"
    
    This reverts commit 67d50f1e6b83b23ce05e64b3f5b96e824c474694.
    
    * Revert "Test without sidebar"
    
    This reverts commit 9cd008403b4daee8fb3accf62356acf23bff9cb1.
    
    * Revert "Click topnav button"
    
    This reverts commit 22b05f769b02994e6e00d88514922966ad913e25.
    
    * Adjust some menu titles
---
 atr/static/css/atr.css              | 100 +++++++++-
 atr/templates/includes/sidebar.html |  11 --
 atr/templates/includes/topnav.html  | 369 ++++++++++++++++++++++++++++++++++++
 atr/templates/layouts/base.html     |  40 +++-
 4 files changed, 499 insertions(+), 21 deletions(-)

diff --git a/atr/static/css/atr.css b/atr/static/css/atr.css
index 67c673d..67486bc 100644
--- a/atr/static/css/atr.css
+++ b/atr/static/css/atr.css
@@ -37,6 +37,59 @@ body {
     font-weight: 425;
 }
 
+.bg-info-light {
+    background-color: #e3f7fc !important;
+}
+
+.dropdown-menu {
+    width: 250px;
+    max-height: 80vh;
+    overflow: hidden auto; /* prevents sideways scrollbars */
+    scrollbar-width: thin;       /* Firefox */
+}
+
+.dropdown-menu::-webkit-scrollbar {
+    width: 8px;                  /* Chrome/Edge */
+}
+
+html {
+    scroll-padding-top: 80px;
+}
+
+.fixed-top {
+    position: fixed;
+    top: 0;
+    right: 0;
+    left: 0;
+    z-index:1030
+}
+
+.user-menu {
+    text-align: center;
+}
+
+.navbar-ribbon {
+    position: relative;
+}
+
+.navbar-ribbon::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+    height: 8px;
+    background: linear-gradient(
+        90deg,
+        #282661 0%,
+        #662f8f 20%,
+        #9e2165 40%,
+        #cb2138 60%,
+        #ea7826 80%,
+        #f7ae18 100%
+    );
+}
+
 footer {
     padding: 1rem;
     background: #eeeeee;
@@ -59,13 +112,13 @@ h1 {
 h2 {
     border-bottom: 1px solid #d1d2d3;
     padding-bottom: 0.5rem;
-    margin-top: 2.5rem;
+    margin-top: 1.5rem;
     margin-bottom: 1.5rem;
 }
 
 h3 {
     font-size: 1.3333rem;
-    margin-top: 1.5rem;
+    margin-top: .5rem;
     font-weight: 525 !important;
 }
 
@@ -266,6 +319,7 @@ span.warning {
 .content {
     flex: 1;
     display: flex;
+    margin-left: 250px;
 }
 
 .main-container {
@@ -292,8 +346,15 @@ aside.sidebar nav a:hover {
 }
 
 .sidebar {
+    position: fixed;
+    left: 0;
+    top: 72px;
+    bottom: 0;
+    height: calc(100vh - 72px); /* ensures the sidebar fills the space below 
the top bar */
+    overflow-y: auto;           /* enables vertical scrolling */
+    z-index: 101;
     width: 250px;
-    background-color: #f6f7f8;
+    background-color: #e3f7fc !important;
     border-right: 1px solid #d1d2d3;
     padding: 1rem;
 }
@@ -334,6 +395,7 @@ aside.sidebar nav a:hover {
     border: none;
     cursor: pointer;
     padding: 0;
+    padding-top: 20px;
     z-index: 100;
 }
 
@@ -350,22 +412,44 @@ aside.sidebar nav a:hover {
     display: none;
 }
 
+
+@media (width <= 990px) {
+    .dropdown-menu {
+       max-height: 40vh;
+    }
+}
+
 @media (width <= 768px) {
     .hamburger {
         display: block;
         position: fixed;
-        top: 20px;
+        top: 72px;
         padding-left: 2rem;
         transition: 0.3s;
     }
 
+    .hamburger::before {
+        content: "";
+        position: absolute;
+        width: 26px;          /* size of the square */
+        height: 32px;
+        bottom: 0;            /* anchor to bottom */
+        right: 0;             /* anchor to right */
+        background: #e3f7fc !important;
+        border-radius: 4px;   /* rounded square */
+        box-shadow: 0 2px 2px rgb(0 0 0 / 20%);
+        z-index: -1;          /* places it behind the icon */
+    }
+
     .sidebar {
         position: fixed;
         left: -250px;
-        top: 20px;
+        top: 72px;
         bottom: 0;
+        height: calc(100vh - 72px); /* ensures the sidebar fills the space 
below the top bar */
+        overflow-y: auto;           /* enables vertical scrolling */
         transition: 0.3s;
-        z-index: 99;
+        z-index: 101;
     }
 
     /* Show sidebar when checkbox is checked */
@@ -394,6 +478,10 @@ aside.sidebar nav a:hover {
         margin-left: 0;
         padding-top: 4rem;
     }
+
+    .content {
+       margin-left: 0;
+    }
 }
 
 /* Flash Messages */
diff --git a/atr/templates/includes/sidebar.html 
b/atr/templates/includes/sidebar.html
index 1bd3fae..aac14b1 100644
--- a/atr/templates/includes/sidebar.html
+++ b/atr/templates/includes/sidebar.html
@@ -1,15 +1,4 @@
 <aside class="sidebar">
-  <div class="sidebar-header">
-    <a href="{{ as_url(get.root.index) }}" class="site-title">
-      <h1>
-        <span class="apache">A<span class="rest">pache</span></span>
-        <br />
-        <span class="trusted">T<span class="rest">rusted</span></span>
-        <br />
-        <span class="release">R<span class="rest">eleases</span></span>
-      </h1>
-    </a>
-  </div>
   <div class="user-section">
     {% if current_user %}
       <div>
diff --git a/atr/templates/includes/topnav.html 
b/atr/templates/includes/topnav.html
new file mode 100644
index 0000000..67269a9
--- /dev/null
+++ b/atr/templates/includes/topnav.html
@@ -0,0 +1,369 @@
+<!-- nav bar -->
+<nav class="navbar navbar-expand-lg navbar-light bg-info-light fixed-top 
navbar-ribbon"
+     aria-label="Fifth navbar example">
+  <div class="container-fluid">
+    <a class="navbar-brand" href="{{ as_url(get.root.index) }}">
+      <img src="https://apache.org/img/asf_logo.png";
+           alt="The Apache Software Foundation"
+           class="asf-logo" />
+      <span class="trusted-releases">Trusted Releases</span>
+    </a>
+    <button class="navbar-toggler"
+            type="button"
+            data-bs-toggle="collapse"
+            data-bs-target="#navbarADP"
+            aria-controls="navbarADP"
+            aria-expanded="false"
+            aria-label="Toggle navigation">
+      <span class="navbar-toggler-icon"></span>
+    </button>
+    <div class="collapse navbar-collapse navbar-adp-offset" id="navbarADP">
+      <ul class="navbar-nav me-auto">
+        {% if current_user %}
+          <li class="nav-item dropdown">
+            <button class="nav-link dropdown-toggle btn"
+                    id="dropdownCandidates"
+                    type="button"
+                    data-bs-toggle="dropdown"
+                    aria-expanded="false"
+                    aria-controls="menuCandidates">Draft</button>
+            <ul class="dropdown-menu"
+                id="menuCandidates"
+                aria-labelledby="dropdownCandidates">
+              <li>
+              <a class="dropdown-item" href="{{ as_url(get.root.index) }}"><i 
class="bi bi-play-circle"></i>
+            Candidates</a>
+          </li>
+          {% set unfinished_releases = 
unfinished_releases_fn(current_user.uid) %}
+          {% if unfinished_releases %}
+            {% for project_short_display_name, project_name, releases in 
unfinished_releases %}
+              <li>
+                <hr class="dropdown-divider" />
+              </li>
+              <li>
+                <a class="dropdown-item fw-bold"
+                   href="{{ as_url(get.projects.view, name=project_name) 
}}">{{ project_short_display_name }}</a>
+              </li>
+              {% for release in releases %}
+                <li>
+                <a class="dropdown-item" href="{{ release_as_url(release) 
}}"><i class="bi bi-tag"></i>
+              {{ release.version }}</a>
+            </li>
+          {% endfor %}
+        {% endfor %}
+      {% endif %}
+      {% set user_projects = user_projects_fn(current_user.uid) %}
+      {% if user_projects %}
+        {% set max_projects = 8 %}
+        <li>
+          <hr class="dropdown-divider" />
+        </li>
+        <li>
+          <a class="dropdown-item fw-bold" href="{{ as_url(get.root.index) 
}}">Start a release</a>
+        </li>
+        {% for project_name, project_full_name in user_projects[:max_projects] 
%}
+          <li>
+          <a class="dropdown-item"
+             href="{{ as_url(get.start.selected, project_name=project_name) 
}}"><i class="bi bi-plus-circle"></i>
+        {{ project_full_name.removeprefix("Apache ").removesuffix(" 
(Incubating)") }}</a>
+      </li>
+    {% endfor %}
+    {% if user_projects|length > max_projects %}
+      <li>
+        <a class="dropdown-item" href="{{ as_url(get.root.index) }}"><i 
class="bi bi-three-dots"></i> {{ user_projects|length - max_projects }} more</a>
+      </li>
+    {% endif %}
+  {% endif %}
+</ul>
+</li>
+{% endif %}
+<li class="nav-item dropdown">
+  <button class="nav-link dropdown-toggle btn"
+          id="dropdownCatalog"
+          type="button"
+          data-bs-toggle="dropdown"
+          aria-expanded="false"
+          aria-controls="menuCatalog">Releases</button>
+  <ul class="dropdown-menu"
+      id="menuCatalog"
+      aria-labelledby="dropdownCatalog">
+    <li>
+    <a class="dropdown-item" href="{{ as_url(get.release.releases) }}"><i 
class="bi bi-view-list"></i>
+  Catalog</a>
+</li>
+<li>
+<a class="dropdown-item" href="{{ as_url(get.committees.directory) }}"><i 
class="bi bi-collection"></i>
+Committees</a>
+</li>
+<li>
+  {# This path is handled by the frontend proxy server #}
+  {# https://djlint.com/docs/ignoring-code/ #}
+  {# djlint:off J018 #} <a class="dropdown-item" href="/downloads/"><i 
class="bi bi-download"></i> Downloads</a> {# djlint:on #}
+</li>
+</ul>
+</li>
+{% if current_user %}
+  <li class="nav-item dropdown">
+    <button class="nav-link dropdown-toggle btn"
+            id="dropdownConfigure"
+            type="button"
+            data-bs-toggle="dropdown"
+            aria-expanded="false"
+            aria-controls="menuCandidates">Configure</button>
+    <ul class="dropdown-menu"
+        id="menuConfigure"
+        aria-labelledby="dropdownConfigure">
+      <li>
+      <a class="dropdown-item" href="{{ as_url(get.committees.directory) 
}}"><i class="bi bi-collection"></i>
+    Committees</a>
+  </li>
+  <li>
+  <a class="dropdown-item" href="{{ as_url(get.projects.projects) }}"><i 
class="bi bi-collection"></i>
+Projects</a>
+</li>
+<!--
+<li>
+<a class="dropdown-item" href="{{ as_url(get.keys.keys) }}"><i class="bi 
bi-key"></i>
+Public keys</a>
+</li>
+-->
+<li>
+<a class="dropdown-item" href="{{ as_url(get.tokens.tokens) }}"><i class="bi 
bi-key"></i>
+API tokens</a>
+</li>
+</ul>
+</li>
+{% endif %}
+<li class="nav-item dropdown">
+  <button class="nav-link dropdown-toggle btn"
+          id="dropdownHelp"
+          type="button"
+          data-bs-toggle="dropdown"
+          aria-expanded="false"
+          aria-controls="menuHelp">Help</button>
+  <ul class="dropdown-menu" id="menuHelp" aria-labelledby="dropdownHelp">
+    {% if current_user %}
+      <li>
+      <a class="dropdown-item" href="{{ as_url(get.root.tutorial) }}"><i 
class="bi bi-book"></i>
+    Tutorial</a>
+  </li>
+{% endif %}
+<li>
+<a class="dropdown-item" href="{{ as_url(get.docs.index) }}"><i class="bi 
bi-book"></i>
+Documentation</a>
+</li>
+<li>
+<a class="dropdown-item" href="{{ as_url(get.root.policies) }}"><i class="bi 
bi-book"></i>
+ASF Policies</a>
+</li>
+{% if current_user %}
+  <li>
+    {# djlint:off J018 #} <a class="dropdown-item" href="/api/docs"><i 
class="bi bi-file-earmark-code"></i>
+    OpenAPI</a> {# djlint:on #}
+  </li>
+  <li>
+    <hr class="dropdown-divider" />
+  </li>
+  <li>
+    <a class="dropdown-item"
+       href="https://github.com/apache/tooling-docs/";
+       target="_blank"><i class="bi bi-github"></i> Tooling Docs</a>
+  </li>
+  <li>
+    <hr class="dropdown-divider" />
+  </li>
+  <li>
+    <a class="dropdown-item"
+       href="https://github.com/apache/tooling-trusted-releases";
+       target="_blank"><i class="bi bi-github"></i> Trusted Releases</a>
+  </li>
+  <li>
+    <a class="dropdown-item"
+       href="https://github.com/apache/tooling-releases-client";
+       target="_blank"><i class="bi bi-github"></i> Trusted Releases Client</a>
+  </li>
+  <li>
+    <a class="dropdown-item"
+       href="https://github.com/apache/tooling-actions";
+       target="_blank"><i class="bi bi-github"></i> Trusted Releases 
Actions</a>
+  </li>
+{% endif %}
+</ul>
+</li>
+{% if is_viewing_as_admin_fn(current_user.uid) %}
+  <li class="nav-item dropdown">
+    <button class="nav-link dropdown-toggle btn"
+            id="dropdownAdmin"
+            type="button"
+            data-bs-toggle="dropdown"
+            aria-expanded="false"
+            aria-controls="menuAdmin">Admin</button>
+    <ul class="dropdown-menu" id="menuAdmin" aria-labelledby="dropdownAdmin">
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.all_releases) }}"
+           {% if request.endpoint == 'atr_admin_all_releases' 
%}class="active"{% endif %}><i class="bi bi-list-ul"></i> All releases</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.browse_as_get) }}"
+           {% if request.endpoint == 'atr_admin_browse_as_get' 
%}class="active"{% endif %}><i class="bi bi-person-plus"></i> Browse as user</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.consistency) }}"
+           {% if request.endpoint == 'atr_admin_consistency' 
%}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Consistency</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.data) }}"
+           {% if request.endpoint == 'atr_admin_data' %}class="active"{% endif 
%}><i class="bi bi-database"></i> Browse database</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.delete_committee_keys_get) }}"
+           {% if request.endpoint == 'atr_admin_delete_committee_keys_get' 
%}class="active"{% endif %}><i class="bi bi-trash"></i> Delete committee 
keys</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.delete_release_get) }}"
+           {% if request.endpoint == 'atr_admin_delete_release_get' 
%}class="active"{% endif %}><i class="bi bi-trash"></i> Delete release</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.env) }}"
+           {% if request.endpoint == 'atr_admin_env' %}class="active"{% endif 
%}><i class="bi bi-gear"></i> Environment</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.keys_check_get) }}"
+           {% if request.endpoint == 'atr_admin_keys_check_get' 
%}class="active"{% endif %}><i class="bi bi-key"></i> Keys check</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.keys_regenerate_all_get) }}"
+           {% if request.endpoint == 'atr_admin_keys_regenerate_all_get' 
%}class="active"{% endif %}><i class="bi bi-key"></i> Regenerate all keys</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.keys_update_get) }}"
+           {% if request.endpoint == 'atr_admin_keys_update_get' 
%}class="active"{% endif %}><i class="bi bi-key"></i> Update keys</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.ldap_get) }}"
+           {% if request.endpoint == 'atr_admin_ldap_get' %}class="active"{% 
endif %}><i class="bi bi-person-plus"></i> LDAP search</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.performance) }}"
+           {% if request.endpoint == 'atr_admin_performance' 
%}class="active"{% endif %}><i class="bi bi-speedometer2"></i> Page 
performance</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.projects_update_get) }}"
+           {% if request.endpoint == 'atr_admin_projects_update_get' 
%}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Update 
projects</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.tasks_) }}"
+           {% if request.endpoint == 'atr_admin_tasks_' %}class="active"{% 
endif %}><i class="bi bi-list-task"></i> Background tasks</a>
+      </li>
+      <li>
+        <hr class="dropdown-divider" />
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.tasks_recent, minutes=5) }}"><i class="bi 
bi-clock-history"></i> Recent tasks</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.toggle_view_get) }}"
+           {% if request.endpoint == 'atr_admin_toggle_view_get' 
%}class="active"{% endif %}><i class="bi bi-person-badge"></i> Toggle admin 
view</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="{{ as_url(admin.validate_) }}"
+           {% if request.endpoint == 'atr_admin_validate_' %}class="active"{% 
endif %}><i class="bi bi-arrow-repeat"></i> Validate</a>
+      </li>
+    </ul>
+  </li>
+{% endif %}
+</ul>
+<ul class="navbar-nav">
+  <li class="nav-item dropdown">
+    <button class="nav-link dropdown-toggle btn"
+            id="dropdownUser"
+            type="button"
+            data-bs-toggle="dropdown"
+            aria-expanded="false"
+            aria-controls="menuUser">
+      Log
+      {% if current_user %}
+        out
+      {% else %}
+        in
+      {% endif %}
+    </button>
+    <ul class="dropdown-menu dropdown-menu-end"
+        id="menuUser"
+        aria-labelledby="dropdownUser">
+      <div class="user-menu">
+        {% if current_user %}
+          <span>{{ current_user.fullname }}</span>
+          (<code>{{ current_user.uid }}</code>)
+          <br />
+          <a href="#"
+             onclick="location.href='/auth?logout=/';"
+             class="logout-link btn btn-sm btn-outline-secondary mt-2">Log 
out</a>
+        {% else %}
+          <a href="#"
+             onclick="location.href='/auth?login=' + window.location.pathname;"
+             class="login-link btn btn-sm btn-secondary">Log in</a>
+        {% endif %}
+      </div>
+    </ul>
+  </li>
+  <li class="nav-item dropdown">
+    <button class="nav-link dropdown-toggle btn"
+            id="dropdownASF"
+            type="button"
+            data-bs-toggle="dropdown"
+            aria-expanded="false"
+            aria-controls="menuASF">About The ASF</button>
+    <ul class="dropdown-menu dropdown-menu-end"
+        id="menuASF"
+        aria-labelledby="dropdownASF">
+      <li>
+        <a class="dropdown-item" href="https://www.apache.org/";>Foundation</a>
+      </li>
+      <li>
+        <hr class="dropdown-divider" />
+      </li>
+      <li>
+        <a class="dropdown-item" 
href="https://www.apache.org/licenses/";>License</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           
href="https://www.apache.org/foundation/sponsorship.html";>Sponsorship</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           href="https://www.apache.org/foundation/thanks.html";>Thanks</a>
+      </li>
+      <li>
+        <hr class="dropdown-divider" />
+      </li>
+      <li>
+        <a class="dropdown-item" 
href="https://www.apache.org/security/";>Security</a>
+      </li>
+      <li>
+        <a class="dropdown-item"
+           
href="https://privacy.apache.org/policies/privacy-policy-public.html";>Privacy 
Policy</a>
+      </li>
+    </ul>
+  </li>
+</ul>
+</div>
+</div>
+</nav>
diff --git a/atr/templates/layouts/base.html b/atr/templates/layouts/base.html
index 1644b4f..476b78f 100644
--- a/atr/templates/layouts/base.html
+++ b/atr/templates/layouts/base.html
@@ -5,7 +5,10 @@
     <meta name="viewport" content="width=device-width,initial-scale=1.0" />
     <meta name="description"
           content="{%- block description -%}{%- endblock description -%}" />
-    <title>{%- block title -%}{%- endblock title -%}</title>
+    <title>
+      {% block title %}
+      {% endblock title %}
+    </title>
 
     <link rel="icon"
           type="image/x-icon"
@@ -16,13 +19,42 @@
       <link rel="stylesheet"
             href="{{ static_url('css/bootstrap-icons.min.css') }}" />
       <link rel="stylesheet" href="{{ static_url('css/bootstrap.custom.css') 
}}" />
+      <style>
+          body {
+              padding-top: 72px;
+          }
+
+          .fixed-top {
+              position: fixed;
+          }
+
+          .asf-logo {
+              height: 42px;
+              margin-left: 6px;
+          }
+
+          .trusted-releases {
+              position: relative;
+              top: -10px;
+              margin-left: 10px;
+              font-weight: 650 !important;
+          }
+
+          .navbar-adp-offset {
+              position: relative;
+              top: 3px;
+              margin-left: 16px;
+          }
+      </style>
     {% endblock stylesheets %}
     {% block head_extra %}
     {% endblock head_extra %}
   </head>
   <body class="{%- block body_class -%}{%- endblock body_class -%}">
-    <div class="wrapper">
-      <div class="ribbon"></div>
+
+    {% include "includes/topnav.html" %}
+
+    <main class="wrapper">
       <div class="content">
         <input type="checkbox" id="nav-toggle" class="nav-toggle" />
         <label for="nav-toggle" class="hamburger" aria-label="Menu">
@@ -50,7 +82,7 @@
 
         </div>
       </div>
-    </div>
+    </main>
 
     {% block javascripts %}
       <script src="{{ static_url('js/bootstrap.bundle.min.js') }}"></script>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to