Add avatar color, initials structure, and admin nav dropdown
Lint / Python (flake8) (push) Failing after 1m7s
Lint / JS (eslint) (push) Successful in 10s
Security / Python Security (bandit) (push) Failing after 1m31s
Test / Python Tests (pytest) (push) Successful in 1m8s
Lint / Notify on failure (push) Successful in 2s
Lint / Deploy (push) Has been skipped
Lint / Python (flake8) (push) Failing after 1m7s
Lint / JS (eslint) (push) Successful in 10s
Security / Python Security (bandit) (push) Failing after 1m31s
Test / Python Tests (pytest) (push) Successful in 1m8s
Lint / Notify on failure (push) Successful in 2s
Lint / Deploy (push) Has been skipped
- app.py: avatar_color Jinja filter using deterministic hash → lt-avatar--orange/green/purple - base.html: proper lt-avatar--sm with lt-avatar-initials span and color class; multi-word initials support - base.html: admin users get lt-nav-dropdown for Suppressions; non-admins see flat link; mobile drawer hides Suppressions for non-admins Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,12 @@ logger = logging.getLogger('gandalf.web')
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
_AVATAR_COLORS = ['lt-avatar--orange', 'lt-avatar--green', 'lt-avatar--purple', '']
|
||||||
|
|
||||||
|
@app.template_filter('avatar_color')
|
||||||
|
def avatar_color_filter(name: str) -> str:
|
||||||
|
return _AVATAR_COLORS[abs(hash(name)) % len(_AVATAR_COLORS)]
|
||||||
|
|
||||||
_cfg = None
|
_cfg = None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+33
-2
@@ -42,9 +42,11 @@
|
|||||||
<a href="{{ url_for('inspector') }}"
|
<a href="{{ url_for('inspector') }}"
|
||||||
class="lt-nav-drawer-link{% if request.endpoint == 'inspector' %} active{% endif %}"
|
class="lt-nav-drawer-link{% if request.endpoint == 'inspector' %} active{% endif %}"
|
||||||
{% if request.endpoint == 'inspector' %}aria-current="page"{% endif %}>Inspector</a>
|
{% if request.endpoint == 'inspector' %}aria-current="page"{% endif %}>Inspector</a>
|
||||||
|
{% if user.groups and 'admin' in user.groups %}
|
||||||
<a href="{{ url_for('suppressions_page') }}"
|
<a href="{{ url_for('suppressions_page') }}"
|
||||||
class="lt-nav-drawer-link{% if request.endpoint == 'suppressions_page' %} active{% endif %}"
|
class="lt-nav-drawer-link{% if request.endpoint == 'suppressions_page' %} active{% endif %}"
|
||||||
{% if request.endpoint == 'suppressions_page' %}aria-current="page"{% endif %}>Suppressions</a>
|
{% if request.endpoint == 'suppressions_page' %}aria-current="page"{% endif %}>Suppressions</a>
|
||||||
|
{% endif %}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div id="lt-nav-overlay" class="lt-nav-drawer-overlay"></div>
|
<div id="lt-nav-overlay" class="lt-nav-drawer-overlay"></div>
|
||||||
@@ -93,20 +95,49 @@
|
|||||||
{% if request.endpoint == 'inspector' %}aria-current="page"{% endif %}>
|
{% if request.endpoint == 'inspector' %}aria-current="page"{% endif %}>
|
||||||
Inspector
|
Inspector
|
||||||
</a>
|
</a>
|
||||||
|
{% if user.groups and 'admin' in user.groups %}
|
||||||
|
<div class="lt-nav-dropdown" data-action="toggle-nav-dropdown">
|
||||||
|
<a href="#"
|
||||||
|
class="lt-nav-link{% if request.endpoint == 'suppressions_page' %} active{% endif %}"
|
||||||
|
role="button"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="lt-admin-dropdown-menu">
|
||||||
|
Admin ▾
|
||||||
|
</a>
|
||||||
|
<ul class="lt-nav-dropdown-menu"
|
||||||
|
id="lt-admin-dropdown-menu"
|
||||||
|
role="menu"
|
||||||
|
aria-label="Admin menu">
|
||||||
|
<li role="none">
|
||||||
|
<a href="{{ url_for('suppressions_page') }}" role="menuitem"
|
||||||
|
class="{% if request.endpoint == 'suppressions_page' %}active{% endif %}">
|
||||||
|
Suppressions
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
<a href="{{ url_for('suppressions_page') }}"
|
<a href="{{ url_for('suppressions_page') }}"
|
||||||
class="lt-nav-link{% if request.endpoint == 'suppressions_page' %} active{% endif %}"
|
class="lt-nav-link{% if request.endpoint == 'suppressions_page' %} active{% endif %}"
|
||||||
{% if request.endpoint == 'suppressions_page' %}aria-current="page"{% endif %}>
|
{% if request.endpoint == 'suppressions_page' %}aria-current="page"{% endif %}>
|
||||||
Suppressions
|
Suppressions
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lt-header-right">
|
<div class="lt-header-right">
|
||||||
{% set _uname = user.name or user.username %}
|
{% set _uname = user.name or user.username %}
|
||||||
<div class="lt-avatar" title="{{ _uname }}" aria-label="{{ _uname }}">{{ _uname[0] | upper }}</div>
|
{% set _words = _uname.split() %}
|
||||||
|
{% set _initials = (_words[0][0] ~ (_words[1][0] if _words|length > 1 else ''))|upper %}
|
||||||
|
<div class="lt-avatar lt-avatar--sm {{ _uname | avatar_color }}"
|
||||||
|
aria-hidden="true" title="{{ _uname }}">
|
||||||
|
<span class="lt-avatar-initials">{{ _initials }}</span>
|
||||||
|
</div>
|
||||||
<span class="lt-header-user">{{ _uname }}</span>
|
<span class="lt-header-user">{{ _uname }}</span>
|
||||||
{% if user.groups and 'admin' in user.groups %}
|
{% if user.groups and 'admin' in user.groups %}
|
||||||
<span class="lt-badge lt-badge-admin">admin</span>
|
<span class="lt-badge lt-badge-admin" aria-label="Administrator">ADMIN</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button type="button" class="lt-theme-btn" id="lt-theme-btn"
|
<button type="button" class="lt-theme-btn" id="lt-theme-btn"
|
||||||
aria-label="Toggle theme" title="Toggle light/dark mode">☀</button>
|
aria-label="Toggle theme" title="Toggle light/dark mode">☀</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user