feat: implement author pages, app layout, and authentication client infrastructure
This commit is contained in:
BIN
public/favicon1.png
Normal file
BIN
public/favicon1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
@@ -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'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
||||
<Link href="/" className="flex items-center space-x-2">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-8 h-8" />
|
||||
<span className="text-xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
||||
<Link href="/" className="flex items-center space-x-2">
|
||||
<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>
|
||||
</Link>
|
||||
<button
|
||||
className="lg:hidden"
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
@@ -251,4 +251,4 @@ export default function AppLayout({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ export const metadata: Metadata = {
|
||||
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.',
|
||||
robots: { index: false, follow: false },
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||
],
|
||||
apple: '/logo.svg',
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
|
||||
],
|
||||
shortcut: '/favicon1.png',
|
||||
apple: '/favicon1.png',
|
||||
},
|
||||
};
|
||||
|
||||
export default function AppGroupLayout({
|
||||
|
||||
@@ -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="w-full max-w-md">
|
||||
<div className="text-center mb-8">
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
|
||||
<span className="text-2xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<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>
|
||||
</Link>
|
||||
<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>
|
||||
</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="w-full max-w-md">
|
||||
<div className="text-center mb-8">
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
|
||||
<span className="text-2xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<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>
|
||||
</Link>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@@ -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="w-full max-w-md">
|
||||
<div className="text-center mb-8">
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
|
||||
<span className="text-2xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<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>
|
||||
</Link>
|
||||
{showPageHeading ? (
|
||||
<h1 className="text-3xl font-bold text-gray-900">Welcome Back</h1>
|
||||
) : (
|
||||
|
||||
@@ -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="w-full max-w-md">
|
||||
<div className="text-center mb-8">
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
|
||||
<span className="text-2xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<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>
|
||||
</Link>
|
||||
<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>
|
||||
</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="w-full max-w-md">
|
||||
<div className="text-center mb-8">
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
|
||||
<span className="text-2xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<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>
|
||||
</Link>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@@ -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="w-full max-w-md">
|
||||
<div className="text-center mb-8">
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
|
||||
<span className="text-2xl font-bold text-gray-900">QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
|
||||
<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>
|
||||
</Link>
|
||||
<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>
|
||||
<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">
|
||||
|
||||
@@ -6,11 +6,12 @@ import { usePathname } from 'next/navigation';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Footer } from '@/components/ui/Footer';
|
||||
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 { cn } from '@/lib/utils';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { allUseCases } from '@/lib/growth-pages';
|
||||
import { industryPages } from '@/lib/industry-pages';
|
||||
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 { AnimatePresence, motion } from 'framer-motion';
|
||||
import { allUseCases } from '@/lib/growth-pages';
|
||||
import { industryPages } from '@/lib/industry-pages';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function MarketingLayout({
|
||||
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">
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex items-center space-x-2.5 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">
|
||||
<QrCode className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span>
|
||||
</Link>
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex items-center space-x-3 group">
|
||||
<div className="relative w-16 h-16 overflow-hidden rounded-full shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200">
|
||||
<Image
|
||||
src="/favicon1.png"
|
||||
alt="QR Master"
|
||||
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 */}
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function AuthorPage({ params }: { params: { slug: string } }) {
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<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>
|
||||
<p className="text-lg text-blue-600 font-medium">{author.role}</p>
|
||||
<p className="text-gray-600 max-w-xl">{author.bio}</p>
|
||||
|
||||
@@ -17,13 +17,13 @@ export const metadata: Metadata = {
|
||||
robots: isIndexable
|
||||
? { index: true, follow: true }
|
||||
: { index: false, follow: false },
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||
],
|
||||
apple: '/logo.svg',
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
|
||||
],
|
||||
shortcut: '/favicon1.png',
|
||||
apple: '/favicon1.png',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@qrmaster',
|
||||
|
||||
@@ -18,14 +18,13 @@ export const metadata: Metadata = {
|
||||
robots: isIndexable
|
||||
? { index: true, follow: true }
|
||||
: { index: false, follow: false },
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.ico', type: 'image/x-icon' },
|
||||
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||
],
|
||||
apple: '/logo.svg',
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
|
||||
],
|
||||
shortcut: '/favicon1.png',
|
||||
apple: '/favicon1.png',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
site: '@qrmaster',
|
||||
@@ -69,4 +68,4 @@ export default function RootLayout({
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import '@/styles/globals.css';
|
||||
export const metadata = {
|
||||
title: 'vCard Download',
|
||||
description: 'Download contact information',
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||
],
|
||||
apple: '/logo.svg',
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
|
||||
],
|
||||
shortcut: '/favicon1.png',
|
||||
apple: '/favicon1.png',
|
||||
},
|
||||
};
|
||||
|
||||
export default function VCardLayout({
|
||||
|
||||
@@ -6,9 +6,10 @@ import { usePathname } from 'next/navigation';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Footer } from '@/components/ui/Footer';
|
||||
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 { cn } from '@/lib/utils';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
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 { AnimatePresence, motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function MarketingLayout({
|
||||
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">
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex items-center space-x-2.5 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">
|
||||
<QrCode className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span>
|
||||
</Link>
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex items-center space-x-3 group">
|
||||
<div className="relative w-16 h-16 overflow-hidden rounded-full shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200">
|
||||
<Image
|
||||
src="/favicon1.png"
|
||||
alt="QR Master"
|
||||
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 */}
|
||||
|
||||
@@ -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.',
|
||||
metadataBase: new URL('https://www.qrmaster.net'),
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||
],
|
||||
apple: '/logo.svg',
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon1.png', sizes: '2048x2048', type: 'image/png' },
|
||||
],
|
||||
shortcut: '/favicon1.png',
|
||||
apple: '/favicon1.png',
|
||||
},
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
siteName: 'QR Master',
|
||||
|
||||
@@ -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="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-8">
|
||||
<div>
|
||||
<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" />
|
||||
<span className={`text-xl font-bold ${isDashboard ? 'text-gray-900' : ''}`}>QR Master</span>
|
||||
</Link>
|
||||
<Link href="/" className="flex items-center space-x-2 mb-4 hover:opacity-80 transition-opacity">
|
||||
<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>
|
||||
</Link>
|
||||
<p className={isDashboard ? 'text-gray-500' : 'text-gray-400'}>
|
||||
{translations.tagline}
|
||||
</p>
|
||||
@@ -136,7 +136,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
|
||||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
<p>© 2025 {translations.rights_reserved}</p>
|
||||
<p>© 2026 {translations.rights_reserved}</p>
|
||||
<div className="w-12"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ export const authors: AuthorProfile[] = [
|
||||
name: "Timo Knuth",
|
||||
role: "Founder, Growth & Product Marketing",
|
||||
bio: "Building QR Master: dynamic QR management, tracking, and bulk ops for B2B teams.",
|
||||
image: "/favicon.svg",
|
||||
image: "/favicon1.png",
|
||||
sameAs: [
|
||||
"https://www.wikidata.org/wiki/Q137919835",
|
||||
"https://www.linkedin.com/in/qr-master-44b6863a2/",
|
||||
|
||||
@@ -154,7 +154,7 @@ export async function sendPasswordResetEmail(email: string, resetToken: string)
|
||||
Secure QR Code Analytics & Management
|
||||
</p>
|
||||
<p style="margin: 0; color: #999999; font-size: 12px;">
|
||||
© 2025 QR Master. All rights reserved.
|
||||
© 2026 QR Master. All rights reserved.
|
||||
</p>
|
||||
<p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;">
|
||||
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>
|
||||
</p>
|
||||
<p style="margin: 0; color: #999999; font-size: 12px;">
|
||||
© 2025 QR Master. All rights reserved.
|
||||
© 2026 QR Master. All rights reserved.
|
||||
</p>
|
||||
<p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;">
|
||||
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>
|
||||
</p>
|
||||
<p style="margin: 0; color: #999999; font-size: 12px;">
|
||||
© 2025 QR Master. All rights reserved.
|
||||
© 2026 QR Master. All rights reserved.
|
||||
</p>
|
||||
<p style="margin: 15px 0 0 0; color: #aaaaaa; font-size: 11px;">
|
||||
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">
|
||||
<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);">
|
||||
<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>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user