Fix favicon not showing issue

- Use url_for() for all favicon and icon references in layout.html
- Add specific routes for favicon files to ensure proper serving
- Create dynamic webmanifest route with correct icon paths
- Import send_from_directory for serving static files
- This ensures favicons work correctly in all deployment scenarios
This commit is contained in:
2025-07-14 11:11:50 +02:00
committed by Jens Luedicke
parent 4fcf4bbf80
commit 4264357d04
9 changed files with 65 additions and 17 deletions

View File

@@ -4,14 +4,14 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% if title == 'Home' %}{{ g.branding.app_name if g.branding else 'TimeTrack' }} - Enterprise Time Tracking & Project Management Software{% else %}{{ title }} - {{ g.branding.app_name if g.branding else 'TimeTrack' }}{% endif %}{% if g.company %} - {{ g.company.name }}{% endif %}</title>
<!-- SEO Meta Tags -->
<meta name="description" content="{% block meta_description %}{{ g.branding.app_name if g.branding else 'TimeTrack' }} is a comprehensive time tracking solution with project management, team collaboration, billing & invoicing. Free, open-source, and enterprise-ready.{% endblock %}">
<meta name="keywords" content="{% block meta_keywords %}time tracking, project management, team collaboration, billing software, invoice management, enterprise time tracker, open source time tracking{% endblock %}">
<meta name="author" content="{{ g.branding.app_name if g.branding else 'TimeTrack' }}">
<meta name="robots" content="index, follow">
<link rel="canonical" href="{{ request.url }}">
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="{% block og_title %}{{ title }} - {{ g.branding.app_name if g.branding else 'TimeTrack' }}{% endblock %}">
<meta property="og:description" content="{% block og_description %}Transform your productivity with intelligent time tracking, project management, and team collaboration tools. Enterprise-grade, open-source solution.{% endblock %}">
@@ -21,7 +21,7 @@
{% if g.branding and g.branding.logo_filename %}
<meta property="og:image" content="{{ url_for('static', filename='uploads/branding/' + g.branding.logo_filename, _external=True) }}">
{% endif %}
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{% block twitter_title %}{{ title }} - {{ g.branding.app_name if g.branding else 'TimeTrack' }}{% endblock %}">
@@ -38,7 +38,7 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/mobile-bottom-nav.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/tablet-optimized.css') }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons@latest/iconfont/tabler-icons.min.css">
<!-- PWA Support -->
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
<meta name="theme-color" content="#667eea">
@@ -54,6 +54,12 @@
{% endif %}
{% if g.branding and g.branding.favicon_filename %}
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='uploads/branding/' + g.branding.favicon_filename) }}">
{% else %}
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='apple-touch-icon.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('static', filename='favicon-16x16.png') }}">
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}">
{% endif %}
<style>
:root {
@@ -98,7 +104,7 @@
<body{% if g.user %} class="has-user has-bottom-nav"{% endif %}>
{% if g.user and g.user.preferences %}
<!-- User preferences for JavaScript -->
<div id="user-preferences" style="display: none;"
<div id="user-preferences" style="display: none;"
data-date-format="{{ g.user.preferences.date_format }}"
data-time-format-24h="{{ g.user.preferences.time_format_24h|lower }}">
</div>
@@ -109,8 +115,8 @@
<div class="mobile-nav-brand">
<a href="{{ url_for('home') }}">
{% if g.branding and g.branding.logo_filename %}
<img src="{{ url_for('static', filename='uploads/branding/' + g.branding.logo_filename) }}"
alt="{{ g.branding.logo_alt_text }}"
<img src="{{ url_for('static', filename='uploads/branding/' + g.branding.logo_filename) }}"
alt="{{ g.branding.logo_alt_text }}"
class="mobile-logo">
{% else %}
{{ g.branding.app_name if g.branding else 'TimeTrack' }}
@@ -133,8 +139,8 @@
<!-- <h2>
<a href="{{ url_for('home') }}">
{% if g.branding and g.branding.logo_filename %}
<img src="{{ url_for('static', filename='uploads/branding/' + g.branding.logo_filename) }}"
alt="{{ g.branding.logo_alt_text }}"
<img src="{{ url_for('static', filename='uploads/branding/' + g.branding.logo_filename) }}"
alt="{{ g.branding.logo_alt_text }}"
class="sidebar-logo">
{% else %}
{{ g.branding.app_name if g.branding else 'TimeTrack' }}
@@ -153,7 +159,7 @@
<img src="{{ g.user.get_avatar_url(32) }}" alt="{{ g.user.username }}" class="user-avatar">
<span class="nav-text">{{ g.user.username }}<span class="dropdown-arrow"></span></span>
</a>
<!-- User Dropdown Context Menu -->
<div class="user-dropdown-modal" id="user-dropdown-modal">
<div class="user-dropdown-header">
@@ -187,7 +193,7 @@
<li><a href="{{ url_for('sprints.sprint_management') }}" data-tooltip="Sprint Management"><i class="nav-icon ti ti-run"></i><span class="nav-text">Sprints</span></a></li>
<li><a href="{{ url_for('notes.notes_list') }}" data-tooltip="Notes"><i class="nav-icon ti ti-notes"></i><span class="nav-text">Notes</span></a></li>
<li><a href="{{ url_for('analytics') }}" data-tooltip="Time Analytics"><i class="nav-icon ti ti-chart-bar"></i><span class="nav-text">Analytics</span></a></li>
<!-- Role-based menu items -->
{% if g.user.role == Role.ADMIN or g.user.role == Role.SYSTEM_ADMIN %}
<li class="nav-divider">Admin</li>
@@ -257,7 +263,7 @@
</div>
{% endif %}
{% endwith %}
<!-- Email Nag Screens -->
{% if g.show_email_nag %}
<div class="email-nag-banner">
@@ -282,7 +288,7 @@
</div>
</div>
{% endif %}
{% block content %}{% endblock %}
</main>
@@ -300,7 +306,7 @@
</div>
</div>
</footer>
<!-- Mobile Bottom Navigation -->
{% if g.user %}
<nav class="mobile-bottom-nav">
@@ -353,7 +359,7 @@
// Store in session storage to not show again this session
sessionStorage.setItem('emailNagDismissed', 'true');
}
// Check if already dismissed this session
if (sessionStorage.getItem('emailNagDismissed') === 'true') {
const banner = document.querySelector('.email-nag-banner');
@@ -365,7 +371,7 @@
{% else %}
<script src="{{ url_for('static', filename='js/splash.js') }}"></script>
{% endif %}
<!-- Custom Tracking Script -->
{% if tracking_script_enabled and tracking_script_code %}
{{ tracking_script_code|safe }}