feat: Enhance BuyMeACoffee visibility with multiple non-intrusive touchpoints

Improve donation visibility by adding multiple strategic placement options
while maintaining a non-intrusive user experience. Removed footer bar that
was causing layout issues and replaced with better alternatives.

Changes:
- Remove footer bar from all pages to fix layout positioning issues
- Add "Support" button in header (visible on md+ screens) with amber gradient styling
- Add dismissible support banner that appears after 2 seconds with 7-day cooldown
- Enhance sidebar BuyMeACoffee link with gradient background and hover effects
- Keep existing dashboard widget for BuyMeACoffee (gradient card in sidebar)
- Add translation strings for new support-related UI elements

The new approach provides multiple touchpoints:
1. Header button - Always visible but subtle
2. Dismissible banner - Appears occasionally, respects user choice
3. Dashboard widget - Contextual placement on main dashboard
4. Sidebar link - Always accessible in navigation

This ensures users can easily find the donation option without being
overwhelmed by intrusive prompts.
This commit is contained in:
Dries Peeters
2025-11-13 09:56:56 +01:00
parent 0c28b80346
commit 9c91f2a26e
3 changed files with 155 additions and 4 deletions

View File

@@ -73,6 +73,22 @@
.sidebar-collapsed #sidebar { width: 4rem !important; overflow-x: hidden; }
/* Shared bulk menu */
.bulk-menu { z-index: 50; max-height: 16rem; overflow-y: auto; }
/* Layout fixes */
#mainContent {
display: flex !important;
flex-direction: column !important;
overflow-x: hidden;
width: 100%;
}
#mainContentAnchor {
flex: 1 0 auto;
min-height: 0;
width: 100%;
overflow-x: auto;
}
/* Ensure body and html don't cause horizontal overflow */
html, body { overflow-x: hidden; }
#appShell { overflow-x: hidden; width: 100%; }
</style>
<script>
// Theme init (unchanged)
@@ -444,9 +460,10 @@
</a>
</li>
<li class="mt-2">
<a href="https://buymeacoffee.com/DryTrix" target="_blank" rel="noopener noreferrer" class="flex items-center p-2 rounded-lg text-text-light dark:text-text-dark hover:bg-background-light dark:hover:bg-background-dark">
<i class="fas fa-mug-saucer w-6 text-center"></i>
<span class="ml-3 sidebar-label">{{ _('Buy me a coffee') }}</span>
<a href="https://buymeacoffee.com/DryTrix" target="_blank" rel="noopener noreferrer" class="flex items-center p-2 rounded-lg bg-gradient-to-r from-amber-500/10 to-orange-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400 hover:from-amber-500/20 hover:to-orange-500/20 hover:border-amber-500/30 transition-all duration-200 group">
<i class="fas fa-mug-saucer w-6 text-center group-hover:scale-110 transition-transform"></i>
<span class="ml-3 sidebar-label font-medium">{{ _('Buy me a coffee') }}</span>
<span class="ml-auto text-xs opacity-70"></span>
</a>
</li>
</ul>
@@ -461,7 +478,7 @@
</aside>
<!-- Main content -->
<div id="mainContent" class="flex-1 flex flex-col transition-all duration-200 ease-in-out lg:ml-64">
<div id="mainContent" class="flex-1 flex flex-col min-h-screen transition-all duration-200 ease-in-out lg:ml-64">
<!-- Header -->
<header class="bg-card-light dark:bg-card-dark p-4 border-b border-border-light dark:border-border-dark flex justify-between items-center">
<!-- Mobile menu button -->
@@ -484,6 +501,16 @@
<!-- Right side controls -->
<div class="flex items-center space-x-4">
<!-- BuyMeACoffee Button -->
<a href="https://buymeacoffee.com/DryTrix"
target="_blank"
rel="noopener noreferrer"
class="hidden md:flex items-center gap-2 px-3 py-1.5 rounded-lg bg-gradient-to-r from-amber-500/10 to-orange-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400 hover:from-amber-500/20 hover:to-orange-500/20 hover:border-amber-500/30 transition-all duration-200 text-sm font-medium"
title="{{ _('Support TimeTracker development') }}">
<i class="fas fa-mug-saucer"></i>
<span class="hidden lg:inline">{{ _('Support') }}</span>
</a>
<button id="theme-toggle" type="button" class="text-text-light dark:text-text-dark hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5" aria-label="{{ _('Toggle dark mode') }}">
<i id="theme-toggle-dark-icon" class="hidden fa-solid fa-moon w-5 h-5"></i>
<i id="theme-toggle-light-icon" class="hidden fa-solid fa-sun w-5 h-5"></i>
@@ -557,6 +584,36 @@
{% endwith %}
</div>
<!-- Dismissible Support Banner -->
<div id="supportBanner" class="hidden bg-gradient-to-r from-amber-50 to-orange-50 dark:from-amber-900/20 dark:to-orange-900/20 border-b border-amber-200 dark:border-amber-800 px-4 py-3">
<div class="max-w-7xl mx-auto flex items-center justify-between gap-4">
<div class="flex items-center gap-3 flex-1">
<i class="fas fa-mug-saucer text-amber-600 dark:text-amber-400 text-lg"></i>
<div class="flex-1">
<p class="text-sm font-medium text-amber-900 dark:text-amber-100">
{{ _('Enjoying TimeTracker?') }}
</p>
<p class="text-xs text-amber-700 dark:text-amber-300">
{{ _('Support continued development with a coffee') }} ☕
</p>
</div>
</div>
<div class="flex items-center gap-2">
<a href="https://buymeacoffee.com/DryTrix"
target="_blank"
rel="noopener noreferrer"
class="px-3 py-1.5 bg-amber-600 hover:bg-amber-700 text-white text-sm font-medium rounded-lg transition-colors">
{{ _('Support') }}
</a>
<button onclick="dismissSupportBanner()"
class="p-1.5 text-amber-600 dark:text-amber-400 hover:bg-amber-100 dark:hover:bg-amber-900/30 rounded transition-colors"
aria-label="{{ _('Dismiss') }}">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<!-- Main page content -->
<main id="mainContentAnchor" class="flex-1 p-6">
{% block content %}{% endblock %}
@@ -1112,6 +1169,41 @@
});
// Close on Escape
document.addEventListener('keydown', function(e){ if (e.key === 'Escape') closeAllMenus(); });
// Support Banner Logic
function dismissSupportBanner() {
const banner = document.getElementById('supportBanner');
if (banner) {
banner.classList.add('hidden');
// Store dismissal timestamp (show again after 7 days)
try {
localStorage.setItem('supportBannerDismissed', Date.now().toString());
} catch(e) {}
}
}
function shouldShowSupportBanner() {
try {
const dismissed = localStorage.getItem('supportBannerDismissed');
if (!dismissed) return true;
const dismissedTime = parseInt(dismissed);
const sevenDays = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
return (Date.now() - dismissedTime) > sevenDays;
} catch(e) {
return true; // Show by default if localStorage fails
}
}
// Show support banner if conditions are met
document.addEventListener('DOMContentLoaded', function() {
const banner = document.getElementById('supportBanner');
if (banner && shouldShowSupportBanner()) {
// Show banner with a slight delay for better UX
setTimeout(() => {
banner.classList.remove('hidden');
}, 2000); // Show after 2 seconds
}
});
</script>
<script src="{{ url_for('static', filename='data-tables-enhanced.js') }}"></script>

View File

@@ -239,6 +239,29 @@
{% endif %}
</div>
</div>
<!-- BuyMeACoffee Widget -->
<div class="bg-gradient-to-br from-amber-500 via-orange-500 to-amber-600 p-6 rounded-lg shadow-lg dashboard-widget animated-card text-white">
<div class="flex items-start justify-between mb-3">
<div class="flex-1">
<h2 class="text-lg font-semibold mb-1">
<i class="fas fa-mug-saucer mr-2"></i>
{{ _('Support TimeTracker') }}
</h2>
<p class="text-sm opacity-90 mb-4">
{{ _('Enjoying TimeTracker? Consider buying me a coffee to support continued development!') }}
</p>
</div>
</div>
<a href="https://buymeacoffee.com/DryTrix"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center justify-center w-full bg-white text-amber-600 px-4 py-3 rounded-lg font-semibold hover:bg-amber-50 transition-all duration-200 shadow-md hover:shadow-lg transform hover:-translate-y-0.5">
<i class="fas fa-mug-saucer mr-2"></i>
{{ _('Buy me a coffee') }}
<i class="fas fa-external-link-alt ml-2 text-xs"></i>
</a>
</div>
</div>
<!-- Delete Entry Confirmation Dialogs -->
{% for entry in recent_entries %}

View File

@@ -1433,6 +1433,42 @@ msgstr "Help"
msgid "Buy me a coffee"
msgstr "Buy me a coffee"
#: app/templates/main/dashboard.html:249
msgid "Support TimeTracker"
msgstr "Support TimeTracker"
#: app/templates/main/dashboard.html:252
msgid "Enjoying TimeTracker? Consider buying me a coffee to support continued development!"
msgstr "Enjoying TimeTracker? Consider buying me a coffee to support continued development!"
#: app/templates/base.html:577
msgid "Made with"
msgstr "Made with"
#: app/templates/base.html:577
msgid "by"
msgstr "by"
#: app/templates/base.html:509
msgid "Support TimeTracker development"
msgstr "Support TimeTracker development"
#: app/templates/base.html:511
msgid "Support"
msgstr "Support"
#: app/templates/base.html:594
msgid "Enjoying TimeTracker?"
msgstr "Enjoying TimeTracker?"
#: app/templates/base.html:597
msgid "Support continued development with a coffee"
msgstr "Support continued development with a coffee"
#: app/templates/base.html:610
msgid "Dismiss"
msgstr "Dismiss"
#: app/templates/base.html:438 app/templates/base.html:439
#: app/templates/tasks/my_tasks.html:115
msgid "Search"