feat: Implement TaskFlow logos and icons throughout the application
continuous-integration/drone/push Build is passing
- Add favicon files (16x16 to 256x256, .ico) - Add PWA icons (128, 256, 512, 1024) - Add apple-touch-icon for iOS - Add transparent icons for loading screens - Add horizontal logo with tagline for auth page - Update HTML head with proper favicon links - Update PWA manifest with correct icon references - Update sidebar header with branded icon - Update mobile header with branded icon - Update auth/login pages with logo display - Update loading state with branded splash screen - Update 404 page with logo header - Update email template to use proper logo URL - Update service worker and push notifications to use correct icons
@@ -15,9 +15,15 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="TaskFlow" />
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" type="image/png" href="/favicon.png?v=4" />
|
||||
<link rel="apple-touch-icon" href="/favicon.png?v=4" />
|
||||
<!-- Favicons -->
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48x48.png" />
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="/favicon-64x64.png" />
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="/favicon-128x128.png" />
|
||||
<link rel="icon" type="image/png" sizes="256x256" href="/favicon-256x256.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
|
||||
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 458 B |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 480 B |
|
Before Width: | Height: | Size: 419 KiB |
|
After Width: | Height: | Size: 773 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 6.8 MiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 7.6 MiB |
|
After Width: | Height: | Size: 6.3 MiB |
|
After Width: | Height: | Size: 6.7 MiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "TaskFlow",
|
||||
"short_name": "TaskFlow",
|
||||
"description": "Gamified task management with AI assistance",
|
||||
"description": "Gamified task management with AI assistance. Focus. Flow. AI.",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#0f0f23",
|
||||
@@ -9,16 +9,31 @@
|
||||
"orientation": "portrait-primary",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
"src": "/icon-128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/favicon.png",
|
||||
"src": "/icon-256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/icon-1024.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"categories": ["productivity", "utilities"],
|
||||
|
||||
@@ -29,8 +29,8 @@ self.addEventListener('push', (event) => {
|
||||
let data = {
|
||||
title: 'TaskFlow',
|
||||
body: 'You have a new notification',
|
||||
icon: '/favicon.png',
|
||||
badge: '/favicon.png',
|
||||
icon: '/icon-256.png',
|
||||
badge: '/icon-128.png',
|
||||
tag: 'taskflow-notification',
|
||||
data: {}
|
||||
};
|
||||
|
||||
@@ -285,8 +285,14 @@ function AppContent() {
|
||||
|
||||
if (isLoadingUser) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen bg-background">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-background gap-6">
|
||||
<div className="w-20 h-20 rounded-2xl bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-2xl animate-pulse">
|
||||
<img src="/icon-transparent-256.png" alt="TaskFlow" className="w-14 h-14 object-contain" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Loader2 className="h-5 w-5 animate-spin text-primary" />
|
||||
<span className="text-muted-foreground text-sm">Loading TaskFlow...</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -341,7 +347,9 @@ function AppContent() {
|
||||
<header className="sticky top-0 z-50 flex items-center gap-3 px-4 py-3 bg-background/80 backdrop-blur-xl border-b border-border/50 md:hidden">
|
||||
<SidebarTrigger className="h-9 w-9" />
|
||||
<div className="flex items-center gap-2">
|
||||
<img src="/favicon.png" alt="Logo" className="w-7 h-7 rounded-lg" />
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-md">
|
||||
<img src="/icon-transparent-128.png" alt="TaskFlow" className="w-6 h-6 object-contain" />
|
||||
</div>
|
||||
<span className="font-bold text-lg">{t('app.title')}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -72,13 +72,13 @@ export function AppSidebar({ user, ...props }: AppSidebarProps) {
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton size="lg" className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground h-14">
|
||||
<div className="flex aspect-square size-9 items-center justify-center rounded-xl overflow-hidden shadow-lg bg-transparent">
|
||||
<img src="/favicon.png" alt="Logo" className="w-full h-full object-cover" />
|
||||
<div className="flex aspect-square size-9 items-center justify-center rounded-xl overflow-hidden shadow-lg bg-gradient-to-br from-violet-600 to-indigo-600">
|
||||
<img src="/icon-transparent-128.png" alt="TaskFlow" className="w-7 h-7 object-contain" />
|
||||
</div>
|
||||
{state !== 'collapsed' && (
|
||||
<div className="grid flex-1 text-left text-sm leading-tight ml-2">
|
||||
<span className="truncate font-bold text-base">{t('app.title')}</span>
|
||||
<span className="truncate text-xs opacity-70">Personal</span>
|
||||
<span className="truncate text-xs opacity-70">Focus. Flow. AI.</span>
|
||||
</div>
|
||||
)}
|
||||
</SidebarMenuButton>
|
||||
|
||||
@@ -145,10 +145,13 @@ export default function AuthPage() {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen grid lg:grid-cols-2 dark">
|
||||
<div className="hidden lg:flex flex-col justify-center items-center bg-zinc-900 p-12 text-white">
|
||||
<div className="max-w-md space-y-4 text-center">
|
||||
<div className="mb-8">
|
||||
<img src="/favicon.png" alt="Logo" className="w-24 h-24" />
|
||||
<div className="hidden lg:flex flex-col justify-center items-center bg-gradient-to-br from-zinc-900 via-zinc-900 to-violet-950 p-12 text-white">
|
||||
<div className="max-w-md space-y-6 text-center">
|
||||
<div className="mb-8 flex flex-col items-center">
|
||||
<div className="w-28 h-28 rounded-2xl bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-2xl mb-6">
|
||||
<img src="/icon-transparent-256.png" alt="TaskFlow" className="w-20 h-20 object-contain" />
|
||||
</div>
|
||||
<img src="/logo-horizontal-tagline-transparent.png" alt="TaskFlow - Focus. Flow. AI." className="h-12 object-contain" />
|
||||
</div>
|
||||
<h1 className="text-4xl font-bold tracking-tight">{t('auth.heroTitle')}</h1>
|
||||
<p className="text-lg text-zinc-400">
|
||||
@@ -162,7 +165,9 @@ export default function AuthPage() {
|
||||
<Card className="w-full max-w-md shadow-xl border-border/50">
|
||||
<CardHeader className="text-center space-y-2">
|
||||
<div className="lg:hidden mx-auto mb-4">
|
||||
<img src="/favicon.png" alt="Logo" className="w-12 h-12 mx-auto" />
|
||||
<div className="w-14 h-14 rounded-xl bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-lg mx-auto">
|
||||
<img src="/icon-transparent-128.png" alt="TaskFlow" className="w-10 h-10 object-contain" />
|
||||
</div>
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-bold">{t('auth.2faVerification')}</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -194,7 +199,9 @@ export default function AuthPage() {
|
||||
<Card className="w-full max-w-md shadow-xl border-border/50">
|
||||
<CardHeader className="text-center space-y-2">
|
||||
<div className="lg:hidden mx-auto mb-4">
|
||||
<img src="/favicon.png" alt="Logo" className="w-12 h-12 mx-auto" />
|
||||
<div className="w-14 h-14 rounded-xl bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-lg mx-auto">
|
||||
<img src="/icon-transparent-128.png" alt="TaskFlow" className="w-10 h-10 object-contain" />
|
||||
</div>
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-bold">{t('auth.welcomeBack')}</CardTitle>
|
||||
<CardDescription>
|
||||
|
||||
@@ -14,7 +14,14 @@ import { Link } from "wouter";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="min-h-screen w-full flex items-center justify-center bg-background p-4">
|
||||
<div className="min-h-screen w-full flex flex-col items-center justify-center bg-background p-4">
|
||||
{/* Logo */}
|
||||
<div className="mb-8 flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-lg">
|
||||
<img src="/icon-transparent-128.png" alt="TaskFlow" className="w-7 h-7 object-contain" />
|
||||
</div>
|
||||
<span className="text-xl font-bold">TaskFlow</span>
|
||||
</div>
|
||||
<Card className="w-full max-w-2xl mx-auto shadow-xl border-dashed border-2 overflow-hidden bg-card text-card-foreground">
|
||||
<div className="md:flex">
|
||||
<div className="md:w-1/2 bg-muted/30 flex items-center justify-center p-8">
|
||||
|
||||
|
After Width: | Height: | Size: 773 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 566 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 925 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 458 B |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 480 B |
|
After Width: | Height: | Size: 7.3 MiB |
|
After Width: | Height: | Size: 8.0 MiB |
|
After Width: | Height: | Size: 6.8 MiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 7.6 MiB |
|
After Width: | Height: | Size: 5.5 MiB |
|
After Width: | Height: | Size: 6.3 MiB |
|
After Width: | Height: | Size: 6.7 MiB |
@@ -12,7 +12,7 @@ export function generateEmailHtml(language: string, content: {
|
||||
: "This email was sent automatically. Please do not reply.";
|
||||
|
||||
const siteUrl = process.env.VITE_PUBLIC_APP_URL || "http://localhost:5001";
|
||||
const logoUrl = `${siteUrl}/favicon.png`;
|
||||
const logoUrl = `${siteUrl}/icon-256.png`;
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
@@ -103,10 +103,7 @@ export function generateEmailHtml(language: string, content: {
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<!-- Trying to link to external URL for logo if accessible, otherwise alt text plays role -->
|
||||
<img src="https://raw.githubusercontent.com/shadcn-ui/ui/main/apps/www/public/favicon.ico" alt="TaskFlow" style="border-radius: 8px;" width="48" height="48">
|
||||
<!-- Ideally we host the logo. For localhost, external clients won't see localhost images. I'll use a placeholder or assume the user will configure a real URL in prod.
|
||||
For now, I'll use a generic pleasing icon or text if image breaks, but let's try to pass the favicon. -->
|
||||
<img src="${logoUrl}" alt="TaskFlow" style="border-radius: 12px;" width="56" height="56">
|
||||
</div>
|
||||
<div class="card">
|
||||
<h1>${content.title}</h1>
|
||||
|
||||
@@ -207,8 +207,8 @@ export async function sendPushNotification(
|
||||
const notificationPayload = JSON.stringify({
|
||||
title: payload.title,
|
||||
body: payload.body,
|
||||
icon: payload.icon || '/favicon.png',
|
||||
badge: payload.badge || '/favicon.png',
|
||||
icon: payload.icon || '/icon-256.png',
|
||||
badge: payload.badge || '/icon-128.png',
|
||||
tag: payload.tag || `taskflow-${Date.now()}`,
|
||||
data: payload.data || {}
|
||||
});
|
||||
|
||||