feat: implement author pages, app layout, and authentication client infrastructure

This commit is contained in:
Timo Knuth
2026-04-08 19:39:01 +02:00
parent 14c3cde7e6
commit cc4afb6f51
17 changed files with 115 additions and 100 deletions

BIN
public/favicon1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -164,11 +164,11 @@ export default function AppLayout({
className={`fixed top-0 left-0 z-50 h-full w-64 bg-white border-r border-gray-200 transform transition-transform lg:translate-x-0 ${sidebarOpen ? 'translate-x-0' : '-translate-x-full' className={`fixed top-0 left-0 z-50 h-full w-64 bg-white border-r border-gray-200 transform transition-transform lg:translate-x-0 ${sidebarOpen ? 'translate-x-0' : '-translate-x-full'
}`} }`}
> >
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<Link href="/" className="flex items-center space-x-2"> <Link href="/" className="flex items-center space-x-2">
<img src="/logo.svg" alt="QR Master" className="w-8 h-8" /> <img src="/favicon1.png" alt="QR Master" className="w-16 h-16 rounded-full object-cover" />
<span className="text-xl font-bold text-gray-900">QR Master</span> <span className="text-xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
<button <button
className="lg:hidden" className="lg:hidden"
onClick={() => setSidebarOpen(false)} onClick={() => setSidebarOpen(false)}
@@ -251,4 +251,4 @@ export default function AppLayout({
</div> </div>
</div> </div>
); );
} }

View File

@@ -8,13 +8,13 @@ export const metadata: Metadata = {
title: 'Dashboard | QR Master', title: 'Dashboard | QR Master',
description: 'Manage your QR Master dashboard. Create dynamic QR codes, view real-time scan analytics, and configure your account settings in one secure place.', description: 'Manage your QR Master dashboard. Create dynamic QR codes, view real-time scan analytics, and configure your account settings in one secure place.',
robots: { index: false, follow: false }, robots: { index: false, follow: false },
icons: { icons: {
icon: [ icon: [
{ url: '/favicon.svg', type: 'image/svg+xml' }, { url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
{ url: '/logo.svg', type: 'image/svg+xml' }, ],
], shortcut: '/favicon1.png',
apple: '/logo.svg', apple: '/favicon1.png',
}, },
}; };
export default function AppGroupLayout({ export default function AppGroupLayout({

View File

@@ -44,10 +44,10 @@ export default function ForgotPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="text-center mb-8"> <div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
<h1 className="text-3xl font-bold text-gray-900">Check Your Email</h1> <h1 className="text-3xl font-bold text-gray-900">Check Your Email</h1>
<p className="text-gray-600 mt-2">We've sent you a password reset link</p> <p className="text-gray-600 mt-2">We've sent you a password reset link</p>
</div> </div>
@@ -98,10 +98,10 @@ export default function ForgotPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="text-center mb-8"> <div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
<h1 className="text-3xl font-bold text-gray-900">Forgot Password?</h1> <h1 className="text-3xl font-bold text-gray-900">Forgot Password?</h1>
<p className="text-gray-600 mt-2">No worries, we'll send you reset instructions</p> <p className="text-gray-600 mt-2">No worries, we'll send you reset instructions</p>
</div> </div>

View File

@@ -79,10 +79,10 @@ export default function LoginClient({ showPageHeading = true }: LoginClientProps
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="text-center mb-8"> <div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
{showPageHeading ? ( {showPageHeading ? (
<h1 className="text-3xl font-bold text-gray-900">Welcome Back</h1> <h1 className="text-3xl font-bold text-gray-900">Welcome Back</h1>
) : ( ) : (

View File

@@ -77,10 +77,10 @@ export default function ResetPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="text-center mb-8"> <div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
<h1 className="text-3xl font-bold text-gray-900">Password Reset Successful</h1> <h1 className="text-3xl font-bold text-gray-900">Password Reset Successful</h1>
<p className="text-gray-600 mt-2">Your password has been updated</p> <p className="text-gray-600 mt-2">Your password has been updated</p>
</div> </div>
@@ -119,10 +119,10 @@ export default function ResetPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="text-center mb-8"> <div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
<h1 className="text-3xl font-bold text-gray-900">Reset Your Password</h1> <h1 className="text-3xl font-bold text-gray-900">Reset Your Password</h1>
<p className="text-gray-600 mt-2">Enter your new password below</p> <p className="text-gray-600 mt-2">Enter your new password below</p>
</div> </div>

View File

@@ -88,10 +88,10 @@ export default function SignupClient() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="text-center mb-8"> <div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link> </Link>
<h1 className="text-3xl font-bold text-gray-900">Create Account</h1> <h1 className="text-3xl font-bold text-gray-900">Create Account</h1>
<p className="text-gray-600 mt-2">Start creating QR codes in seconds</p> <p className="text-gray-600 mt-2">Start creating QR codes in seconds</p>
<Link href="/" className="text-sm text-primary-600 hover:text-primary-700 font-medium mt-2 inline-block border border-primary-600 hover:border-primary-700 px-4 py-2 rounded-lg transition-colors"> <Link href="/" className="text-sm text-primary-600 hover:text-primary-700 font-medium mt-2 inline-block border border-primary-600 hover:border-primary-700 px-4 py-2 rounded-lg transition-colors">

View File

@@ -6,11 +6,12 @@ import { usePathname } from 'next/navigation';
import { Button } from '@/components/ui/Button'; import { Button } from '@/components/ui/Button';
import { Footer } from '@/components/ui/Footer'; import { Footer } from '@/components/ui/Footer';
import en from '@/i18n/en.json'; import en from '@/i18n/en.json';
import { ChevronDown, BookOpen, Building2, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Barcode as BarcodeIcon, Star } from 'lucide-react'; import { ChevronDown, BookOpen, Building2, Wifi, Contact, MessageCircle, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Barcode as BarcodeIcon, Star } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { allUseCases } from '@/lib/growth-pages'; import { allUseCases } from '@/lib/growth-pages';
import { industryPages } from '@/lib/industry-pages'; import { industryPages } from '@/lib/industry-pages';
import Image from 'next/image';
export default function MarketingLayout({ export default function MarketingLayout({
children, children,
@@ -141,13 +142,20 @@ export default function MarketingLayout({
> >
<nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between"> <nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between">
{/* Logo */} {/* Logo */}
<Link href="/" className="flex items-center space-x-2.5 group"> <Link href="/" className="flex items-center space-x-3 group">
<div className="relative w-9 h-9 flex items-center justify-center bg-indigo-600 rounded-lg shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200"> <div className="relative w-16 h-16 overflow-hidden rounded-full shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200">
<QrCode className="w-5 h-5 text-white" /> <Image
</div> src="/favicon1.png"
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span> alt="QR Master"
</Link> fill
sizes="64px"
className="object-cover"
priority
/>
</div>
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span>
</Link>
{/* Desktop Navigation */} {/* Desktop Navigation */}

View File

@@ -59,7 +59,7 @@ export default function AuthorPage({ params }: { params: { slug: string } }) {
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<h1 className="text-3xl font-extrabold text-gray-900">{author.name}</h1> <h1 className="text-3xl font-extrabold text-gray-900">{author.name}</h1>
<Image src="/logo.svg" alt="QR Master" width={24} height={24} className="opacity-80" /> <Image src="/favicon1.png" alt="QR Master" width={24} height={24} className="rounded-full object-cover opacity-90" />
</div> </div>
<p className="text-lg text-blue-600 font-medium">{author.role}</p> <p className="text-lg text-blue-600 font-medium">{author.role}</p>
<p className="text-gray-600 max-w-xl">{author.bio}</p> <p className="text-gray-600 max-w-xl">{author.bio}</p>

View File

@@ -17,13 +17,13 @@ export const metadata: Metadata = {
robots: isIndexable robots: isIndexable
? { index: true, follow: true } ? { index: true, follow: true }
: { index: false, follow: false }, : { index: false, follow: false },
icons: { icons: {
icon: [ icon: [
{ url: '/favicon.svg', type: 'image/svg+xml' }, { url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
{ url: '/logo.svg', type: 'image/svg+xml' }, ],
], shortcut: '/favicon1.png',
apple: '/logo.svg', apple: '/favicon1.png',
}, },
twitter: { twitter: {
card: 'summary_large_image', card: 'summary_large_image',
site: '@qrmaster', site: '@qrmaster',

View File

@@ -18,14 +18,13 @@ export const metadata: Metadata = {
robots: isIndexable robots: isIndexable
? { index: true, follow: true } ? { index: true, follow: true }
: { index: false, follow: false }, : { index: false, follow: false },
icons: { icons: {
icon: [ icon: [
{ url: '/favicon.ico', type: 'image/x-icon' }, { url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
{ url: '/favicon.svg', type: 'image/svg+xml' }, ],
{ url: '/logo.svg', type: 'image/svg+xml' }, shortcut: '/favicon1.png',
], apple: '/favicon1.png',
apple: '/logo.svg', },
},
twitter: { twitter: {
card: 'summary_large_image', card: 'summary_large_image',
site: '@qrmaster', site: '@qrmaster',
@@ -69,4 +68,4 @@ export default function RootLayout({
</body> </body>
</html> </html>
); );
} }

View File

@@ -4,13 +4,13 @@ import '@/styles/globals.css';
export const metadata = { export const metadata = {
title: 'vCard Download', title: 'vCard Download',
description: 'Download contact information', description: 'Download contact information',
icons: { icons: {
icon: [ icon: [
{ url: '/favicon.svg', type: 'image/svg+xml' }, { url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
{ url: '/logo.svg', type: 'image/svg+xml' }, ],
], shortcut: '/favicon1.png',
apple: '/logo.svg', apple: '/favicon1.png',
}, },
}; };
export default function VCardLayout({ export default function VCardLayout({

View File

@@ -6,9 +6,10 @@ import { usePathname } from 'next/navigation';
import { Button } from '@/components/ui/Button'; import { Button } from '@/components/ui/Button';
import { Footer } from '@/components/ui/Footer'; import { Footer } from '@/components/ui/Footer';
import de from '@/i18n/de.json'; import de from '@/i18n/de.json';
import { ChevronDown, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Barcode as BarcodeIcon } from 'lucide-react'; import { ChevronDown, Wifi, Contact, MessageCircle, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Barcode as BarcodeIcon } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import Image from 'next/image';
export default function MarketingLayout({ export default function MarketingLayout({
children, children,
@@ -108,13 +109,20 @@ export default function MarketingLayout({
> >
<nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between"> <nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between">
{/* Logo */} {/* Logo */}
<Link href="/" className="flex items-center space-x-2.5 group"> <Link href="/" className="flex items-center space-x-3 group">
<div className="relative w-9 h-9 flex items-center justify-center bg-indigo-600 rounded-lg shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200"> <div className="relative w-16 h-16 overflow-hidden rounded-full shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200">
<QrCode className="w-5 h-5 text-white" /> <Image
</div> src="/favicon1.png"
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span> alt="QR Master"
</Link> fill
sizes="64px"
className="object-cover"
priority
/>
</div>
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span>
</Link>
{/* Desktop Navigation */} {/* Desktop Navigation */}

View File

@@ -13,13 +13,13 @@ export const metadata: Metadata = {
}, },
description: 'Erstellen Sie dynamische QR Codes für Feedback, PDF, Coupons und App Stores. Verfolgen Sie Scans und skalieren Sie Kampagnen mit sicheren Analysen.', description: 'Erstellen Sie dynamische QR Codes für Feedback, PDF, Coupons und App Stores. Verfolgen Sie Scans und skalieren Sie Kampagnen mit sicheren Analysen.',
metadataBase: new URL('https://www.qrmaster.net'), metadataBase: new URL('https://www.qrmaster.net'),
icons: { icons: {
icon: [ icon: [
{ url: '/favicon.svg', type: 'image/svg+xml' }, { url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
{ url: '/logo.svg', type: 'image/svg+xml' }, ],
], shortcut: '/favicon1.png',
apple: '/logo.svg', apple: '/favicon1.png',
}, },
openGraph: { openGraph: {
type: 'website', type: 'website',
siteName: 'QR Master', siteName: 'QR Master',

View File

@@ -19,10 +19,10 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl"> <div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-8"> <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-8">
<div> <div>
<Link href="/" className="flex items-center space-x-2 mb-4 hover:opacity-80 transition-opacity"> <Link href="/" className="flex items-center space-x-2 mb-4 hover:opacity-80 transition-opacity">
<img src="/logo.svg" alt="QR Master Logo" className="w-10 h-10" /> <img src="/favicon1.png" alt="QR Master Logo" className="w-[68px] h-[68px] rounded-full object-cover" />
<span className={`text-xl font-bold ${isDashboard ? 'text-gray-900' : ''}`}>QR Master</span> <span className={`text-xl font-bold ${isDashboard ? 'text-gray-900' : ''}`}>QR Master</span>
</Link> </Link>
<p className={isDashboard ? 'text-gray-500' : 'text-gray-400'}> <p className={isDashboard ? 'text-gray-500' : 'text-gray-400'}>
{translations.tagline} {translations.tagline}
</p> </p>
@@ -136,7 +136,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
) : ( ) : (
<div></div> <div></div>
)} )}
<p>&copy; 2025 {translations.rights_reserved}</p> <p>&copy; 2026 {translations.rights_reserved}</p>
<div className="w-12"></div> <div className="w-12"></div>
</div> </div>
</div> </div>

View File

@@ -6,7 +6,7 @@ export const authors: AuthorProfile[] = [
name: "Timo Knuth", name: "Timo Knuth",
role: "Founder, Growth & Product Marketing", role: "Founder, Growth & Product Marketing",
bio: "Building QR Master: dynamic QR management, tracking, and bulk ops for B2B teams.", bio: "Building QR Master: dynamic QR management, tracking, and bulk ops for B2B teams.",
image: "/favicon.svg", image: "/favicon1.png",
sameAs: [ sameAs: [
"https://www.wikidata.org/wiki/Q137919835", "https://www.wikidata.org/wiki/Q137919835",
"https://www.linkedin.com/in/qr-master-44b6863a2/", "https://www.linkedin.com/in/qr-master-44b6863a2/",

View File

@@ -154,7 +154,7 @@ export async function sendPasswordResetEmail(email: string, resetToken: string)
Secure QR Code Analytics & Management Secure QR Code Analytics & Management
</p> </p>
<p style="margin: 0; color: #999999; font-size: 12px;"> <p style="margin: 0; color: #999999; font-size: 12px;">
© 2025 QR Master. All rights reserved. © 2026 QR Master. All rights reserved.
</p> </p>
<p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;"> <p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;">
This is an automated security email. Please do not reply. This is an automated security email. Please do not reply.
@@ -326,7 +326,7 @@ export async function sendNewsletterWelcomeEmail(email: string) {
<a href="https://www.qrmaster.net" style="color: #667eea; text-decoration: none;">www.qrmaster.net</a> <a href="https://www.qrmaster.net" style="color: #667eea; text-decoration: none;">www.qrmaster.net</a>
</p> </p>
<p style="margin: 0; color: #999999; font-size: 12px;"> <p style="margin: 0; color: #999999; font-size: 12px;">
© 2025 QR Master. All rights reserved. © 2026 QR Master. All rights reserved.
</p> </p>
<p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;"> <p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;">
You're receiving this because you signed up for AI feature notifications. You're receiving this because you signed up for AI feature notifications.
@@ -506,7 +506,7 @@ export async function sendAIFeatureLaunchEmail(email: string) {
<a href="https://www.qrmaster.net/faq" style="color: #667eea; text-decoration: none;">Help</a> <a href="https://www.qrmaster.net/faq" style="color: #667eea; text-decoration: none;">Help</a>
</p> </p>
<p style="margin: 0; color: #999999; font-size: 12px;"> <p style="margin: 0; color: #999999; font-size: 12px;">
© 2025 QR Master. All rights reserved. © 2026 QR Master. All rights reserved.
</p> </p>
<p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;"> <p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;">
You received this because you subscribed to AI feature launch notifications. You received this because you subscribed to AI feature launch notifications.
@@ -806,7 +806,7 @@ export async function sendWelcomeEmail(email: string, name: string) {
<table role="presentation" cellpadding="0" cellspacing="0" border="0"> <table role="presentation" cellpadding="0" cellspacing="0" border="0">
<tr> <tr>
<td style="width:56px; height:56px; background-color:#0B0D14; border-radius:50%; text-align:center; vertical-align:middle; border:2px solid ${clr.border}; box-shadow:0 4px 10px rgba(0,0,0,0.05);"> <td style="width:56px; height:56px; background-color:#0B0D14; border-radius:50%; text-align:center; vertical-align:middle; border:2px solid ${clr.border}; box-shadow:0 4px 10px rgba(0,0,0,0.05);">
<img src="${appUrl}/favicon.svg" width="32" height="32" alt="Timo" style="display:inline-block; vertical-align:middle;"> <img src="${appUrl}/favicon1.png" width="32" height="32" alt="Timo" style="display:inline-block; vertical-align:middle; border-radius:50%; object-fit:cover;">
</td> </td>
</tr> </tr>
</table> </table>