MVP fertig
This commit is contained in:
@@ -32,11 +32,6 @@ export default function ClientSidePage() {
|
||||
title: "Zero Data Storage",
|
||||
description: "We don't store any passwords, user data, or personal information. Everything is processed locally and immediately discarded."
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Open Source Verification",
|
||||
description: "All code is publicly available and auditable. You can verify our security claims by reviewing the source code."
|
||||
}
|
||||
]
|
||||
|
||||
const technicalDetails = [
|
||||
@@ -98,7 +93,7 @@ export default function ClientSidePage() {
|
||||
className="flex items-center text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5 mr-2" />
|
||||
Zurück zu PassMaster
|
||||
Back to PassMaster
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -118,10 +113,10 @@ export default function ClientSidePage() {
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
Client-Side Sicherheit
|
||||
Client-Side Security
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
||||
Maximale Sicherheit durch lokale Verarbeitung. Ihre Passwörter werden ausschließlich in Ihrem Browser generiert und verlassen niemals Ihr Gerät.
|
||||
Maximum security through local processing. Your passwords are generated exclusively in your browser and never leave your device.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -135,14 +130,14 @@ export default function ClientSidePage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Sicherheits-Features
|
||||
Security Features
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Jeder Aspekt von PassMaster ist darauf ausgelegt, Ihre Sicherheit zu maximieren.
|
||||
Every aspect of PassMaster is designed to maximize your security.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{securityFeatures.map((feature, index) => (
|
||||
<motion.div
|
||||
key={feature.title}
|
||||
@@ -182,10 +177,10 @@ export default function ClientSidePage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Warum Client-Side Sicherheit?
|
||||
Why Client-Side Security?
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Die Vorteile der lokalen Passwort-Generierung.
|
||||
The benefits of local password generation.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -225,10 +220,10 @@ export default function ClientSidePage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Technische Details
|
||||
Technical Details
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Wie PassMaster Ihre Sicherheit gewährleistet.
|
||||
How PassMaster ensures your security.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -270,28 +265,24 @@ export default function ClientSidePage() {
|
||||
<div className="flex items-center mb-6">
|
||||
<FileText className="h-8 w-8 text-green-600 mr-3" />
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
||||
Technische Implementierung
|
||||
Technical Implementation
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="prose dark:prose-invert max-w-none">
|
||||
<h3 className="text-lg font-semibold mb-4">Wie PassMaster funktioniert</h3>
|
||||
<h3 className="text-lg font-semibold mb-4">How PassMaster Works</h3>
|
||||
<ul className="space-y-3 text-gray-600 dark:text-gray-300">
|
||||
<li className="flex items-start space-x-3">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>Lokale Verarbeitung:</strong> Alle Passwort-Generierung erfolgt in Ihrem Browser mit JavaScript</span>
|
||||
<span><strong>Local Processing:</strong> All password generation happens in your browser using JavaScript</span>
|
||||
</li>
|
||||
<li className="flex items-start space-x-3">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>Keine Netzwerk-Anfragen:</strong> Die App funktioniert nach dem ersten Laden vollständig offline</span>
|
||||
<span><strong>No Network Requests:</strong> The app works completely offline after initial load</span>
|
||||
</li>
|
||||
<li className="flex items-start space-x-3">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>Open Source:</strong> Der gesamte Code ist öffentlich auf GitHub verfügbar zur Überprüfung</span>
|
||||
</li>
|
||||
<li className="flex items-start space-x-3">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>Keine Abhängigkeiten:</strong> Wir verwenden keine externen Services oder Drittanbieter-Bibliotheken</span>
|
||||
<span><strong>No Dependencies:</strong> We don't use external services or third-party libraries</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -308,26 +299,18 @@ export default function ClientSidePage() {
|
||||
className="bg-green-50 dark:bg-green-900/20 rounded-lg p-8"
|
||||
>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Fragen zur Sicherheit?
|
||||
Questions About Security?
|
||||
</h2>
|
||||
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
||||
Wir sind verpflichtet zu Transparenz. Wenn Sie Fragen zu unseren Sicherheitspraktiken haben,
|
||||
überprüfen Sie unseren Quellcode oder kontaktieren Sie uns.
|
||||
We are committed to transparency. If you have questions about our security practices,
|
||||
please contact us.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a
|
||||
href="https://github.com/your-repo/passmaster"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-green-600 hover:bg-green-700 transition-colors"
|
||||
>
|
||||
Quellcode ansehen
|
||||
</a>
|
||||
<div className="flex justify-center">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-gray-300 dark:border-gray-600 text-base font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
Zum Generator
|
||||
Back to Generator
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -17,88 +17,88 @@ export default function ExcludeSimilarPage() {
|
||||
const readabilityFeatures = [
|
||||
{
|
||||
icon: Eye,
|
||||
title: "Ähnliche Zeichen ausschließen",
|
||||
description: "Verwirrende Zeichen wie 0/O, 1/l/I werden automatisch ausgeschlossen, um Lesbarkeit zu verbessern."
|
||||
title: "Exclude Similar Characters",
|
||||
description: "Confusing characters like 0/O, 1/l/I are automatically excluded to improve readability."
|
||||
},
|
||||
{
|
||||
icon: BookOpen,
|
||||
title: "Bessere Lesbarkeit",
|
||||
description: "Passwörter sind leichter zu lesen und zu tippen, ohne die Sicherheit zu beeinträchtigen."
|
||||
title: "Better Readability",
|
||||
description: "Passwords are easier to read and type without compromising security."
|
||||
},
|
||||
{
|
||||
icon: Target,
|
||||
title: "Weniger Fehler",
|
||||
description: "Reduziert Tippfehler beim manuellen Eingeben von Passwörtern erheblich."
|
||||
title: "Fewer Errors",
|
||||
description: "Significantly reduces typing errors when manually entering passwords."
|
||||
},
|
||||
{
|
||||
icon: Users,
|
||||
title: "Benutzerfreundlich",
|
||||
description: "Besonders nützlich für ältere Benutzer oder bei der Eingabe auf mobilen Geräten."
|
||||
title: "User-Friendly",
|
||||
description: "Especially useful for older users or when typing on mobile devices."
|
||||
}
|
||||
]
|
||||
|
||||
const excludedCharacters = [
|
||||
{
|
||||
category: "Zahlen und Buchstaben",
|
||||
characters: ["0 (Null)", "O (Großes O)", "1 (Eins)", "l (kleines L)", "I (Großes i)"],
|
||||
reason: "Diese Zeichen sehen in vielen Schriftarten identisch aus"
|
||||
category: "Numbers and Letters",
|
||||
characters: ["0 (Zero)", "O (Capital O)", "1 (One)", "l (lowercase L)", "I (Capital I)"],
|
||||
reason: "These characters look identical in many fonts"
|
||||
},
|
||||
{
|
||||
category: "Sonderzeichen",
|
||||
characters: ["| (Pipe)", "` (Backtick)", "' (Apostroph)", "\" (Anführungszeichen)"],
|
||||
reason: "Können in verschiedenen Kontexten verwirrend sein"
|
||||
category: "Special Characters",
|
||||
characters: ["| (Pipe)", "` (Backtick)", "' (Apostrophe)", "\" (Quotation marks)"],
|
||||
reason: "Can be confusing in different contexts"
|
||||
},
|
||||
{
|
||||
category: "Leerzeichen",
|
||||
characters: [" (Leerzeichen)", " (Mehrfache Leerzeichen)"],
|
||||
reason: "Können beim Kopieren/Einfügen Probleme verursachen"
|
||||
category: "Spaces",
|
||||
characters: [" (Space)", " (Multiple spaces)"],
|
||||
reason: "Can cause problems when copying/pasting"
|
||||
}
|
||||
]
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
icon: Zap,
|
||||
title: "Schnellere Eingabe",
|
||||
description: "Weniger Verwirrung beim manuellen Tippen von Passwörtern."
|
||||
title: "Faster Input",
|
||||
description: "Less confusion when manually typing passwords."
|
||||
},
|
||||
{
|
||||
icon: CheckCircle,
|
||||
title: "Weniger Fehler",
|
||||
description: "Reduziert Tippfehler und damit verbundene Frustration."
|
||||
title: "Fewer Errors",
|
||||
description: "Reduces typing errors and associated frustration."
|
||||
},
|
||||
{
|
||||
icon: Eye,
|
||||
title: "Bessere UX",
|
||||
description: "Verbessert die Benutzererfahrung ohne Sicherheitsverlust."
|
||||
title: "Better UX",
|
||||
description: "Improves user experience without security loss."
|
||||
}
|
||||
]
|
||||
|
||||
const securityImpact = [
|
||||
{
|
||||
title: "Sicherheit bleibt hoch",
|
||||
title: "Security Remains High",
|
||||
items: [
|
||||
"Entropie wird nur minimal reduziert",
|
||||
"Noch immer über 80 Zeichen verfügbar",
|
||||
"Kryptographisch sichere Generierung",
|
||||
"Ausreichend für alle praktischen Zwecke"
|
||||
"Entropy is only minimally reduced",
|
||||
"Still over 80 characters available",
|
||||
"Cryptographically secure generation",
|
||||
"Sufficient for all practical purposes"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Praktische Vorteile",
|
||||
title: "Practical Benefits",
|
||||
items: [
|
||||
"Einfachere manuelle Eingabe",
|
||||
"Weniger Support-Anfragen",
|
||||
"Bessere Benutzerakzeptanz",
|
||||
"Reduzierte Fehlerrate"
|
||||
"Easier manual input",
|
||||
"Fewer support requests",
|
||||
"Better user acceptance",
|
||||
"Reduced error rate"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Empfohlene Verwendung",
|
||||
title: "Recommended Usage",
|
||||
items: [
|
||||
"Für manuell eingegebene Passwörter",
|
||||
"Bei älteren Benutzern",
|
||||
"Auf mobilen Geräten",
|
||||
"In Umgebungen mit schlechter Sichtbarkeit"
|
||||
"For manually entered passwords",
|
||||
"For older users",
|
||||
"On mobile devices",
|
||||
"In environments with poor visibility"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -114,7 +114,7 @@ export default function ExcludeSimilarPage() {
|
||||
className="flex items-center text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5 mr-2" />
|
||||
Zurück zu PassMaster
|
||||
Back to PassMaster
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -134,11 +134,11 @@ export default function ExcludeSimilarPage() {
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
Lesbarkeit & Benutzerfreundlichkeit
|
||||
Readability & User-Friendliness
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
||||
Verbessern Sie die Lesbarkeit Ihrer Passwörter ohne Sicherheit zu opfern.
|
||||
Ähnliche Zeichen werden automatisch ausgeschlossen.
|
||||
Improve the readability of your passwords without sacrificing security.
|
||||
Similar characters are automatically excluded.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -152,10 +152,10 @@ export default function ExcludeSimilarPage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Lesbarkeits-Features
|
||||
Readability Features
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Wie PassMaster die Benutzerfreundlichkeit verbessert.
|
||||
How PassMaster improves user-friendliness.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -199,10 +199,10 @@ export default function ExcludeSimilarPage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Ausgeschlossene Zeichen
|
||||
Excluded Characters
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Diese Zeichen werden automatisch ausgeschlossen, um Verwirrung zu vermeiden.
|
||||
These characters are automatically excluded to avoid confusion.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -245,10 +245,10 @@ export default function ExcludeSimilarPage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Vorteile der Lesbarkeit
|
||||
Benefits of Readability
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Warum lesbare Passwörter wichtig sind.
|
||||
Why readable passwords are important.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -288,10 +288,10 @@ export default function ExcludeSimilarPage() {
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Sicherheit vs. Lesbarkeit
|
||||
Security vs. Readability
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||
Wie wir das perfekte Gleichgewicht finden.
|
||||
How we find the perfect balance.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
@@ -331,20 +331,20 @@ export default function ExcludeSimilarPage() {
|
||||
className="bg-white dark:bg-gray-800 rounded-lg p-8 shadow-sm border border-gray-200 dark:border-gray-700"
|
||||
>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-6 text-center">
|
||||
Beispiel-Vergleich
|
||||
Example Comparison
|
||||
</h2>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
|
||||
<XCircle className="h-5 w-5 text-red-500 mr-2" />
|
||||
Ohne Lesbarkeits-Filter
|
||||
Without Readability Filter
|
||||
</h3>
|
||||
<div className="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg font-mono text-sm">
|
||||
<div className="text-red-600 dark:text-red-400 mb-2">Schwer lesbar:</div>
|
||||
<div className="text-red-600 dark:text-red-400 mb-2">Hard to read:</div>
|
||||
<div>K9mP0lI|nQ2v</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Verwirrende Zeichen: 0, l, I, |
|
||||
Confusing characters: 0, l, I, |
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -352,13 +352,13 @@ export default function ExcludeSimilarPage() {
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mr-2" />
|
||||
Mit Lesbarkeits-Filter
|
||||
With Readability Filter
|
||||
</h3>
|
||||
<div className="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg font-mono text-sm">
|
||||
<div className="text-green-600 dark:text-green-400 mb-2">Leicht lesbar:</div>
|
||||
<div className="text-green-600 dark:text-green-400 mb-2">Easy to read:</div>
|
||||
<div>K9mP3nQ2vX7w</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Keine verwirrenden Zeichen
|
||||
No confusing characters
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -376,24 +376,24 @@ export default function ExcludeSimilarPage() {
|
||||
className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-8"
|
||||
>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Bereit für bessere Lesbarkeit?
|
||||
Ready for Better Readability?
|
||||
</h2>
|
||||
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
||||
Aktivieren Sie die Lesbarkeits-Option in PassMaster und generieren Sie
|
||||
benutzerfreundliche, aber dennoch sichere Passwörter.
|
||||
Enable the readability option in PassMaster and generate
|
||||
user-friendly, yet secure passwords.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Jetzt ausprobieren
|
||||
Try Now
|
||||
</Link>
|
||||
<Link
|
||||
href="/client-side"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-gray-300 dark:border-gray-600 text-base font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
Sicherheit erfahren
|
||||
Learn About Security
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
346
app/offline/page.tsx
Normal file
346
app/offline/page.tsx
Normal file
@@ -0,0 +1,346 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import {
|
||||
Wifi,
|
||||
WifiOff,
|
||||
Download,
|
||||
Shield,
|
||||
CheckCircle,
|
||||
AlertCircle,
|
||||
Smartphone,
|
||||
Monitor
|
||||
} from 'lucide-react'
|
||||
|
||||
export default function OfflinePage() {
|
||||
const [isOnline, setIsOnline] = useState(true)
|
||||
const [isInstallable, setIsInstallable] = useState(false)
|
||||
const [deferredPrompt, setDeferredPrompt] = useState<any>(null)
|
||||
|
||||
useEffect(() => {
|
||||
setIsOnline(navigator.onLine)
|
||||
|
||||
const handleOnline = () => setIsOnline(true)
|
||||
const handleOffline = () => setIsOnline(false)
|
||||
|
||||
window.addEventListener('online', handleOnline)
|
||||
window.addEventListener('offline', handleOffline)
|
||||
|
||||
// PWA install prompt
|
||||
const handleBeforeInstallPrompt = (e: any) => {
|
||||
e.preventDefault()
|
||||
setDeferredPrompt(e)
|
||||
setIsInstallable(true)
|
||||
}
|
||||
|
||||
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('online', handleOnline)
|
||||
window.removeEventListener('offline', handleOffline)
|
||||
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleInstallClick = async () => {
|
||||
if (deferredPrompt) {
|
||||
deferredPrompt.prompt()
|
||||
const { outcome } = await deferredPrompt.userChoice
|
||||
if (outcome === 'accepted') {
|
||||
setDeferredPrompt(null)
|
||||
setIsInstallable(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const offlineFeatures = [
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Complete Offline Functionality",
|
||||
description: "All password generation features work without internet connection. Service Worker ensures local availability."
|
||||
},
|
||||
{
|
||||
icon: WifiOff,
|
||||
title: "No Data Transmission",
|
||||
description: "100% client-side processing. Your passwords never leave your device, even in online mode."
|
||||
},
|
||||
{
|
||||
icon: Download,
|
||||
title: "PWA Installation",
|
||||
description: "Install PassMaster as a native app. Works on desktop, tablet and smartphone."
|
||||
}
|
||||
]
|
||||
|
||||
const installSteps = [
|
||||
{
|
||||
step: 1,
|
||||
title: "Browser Installation",
|
||||
description: "Click 'Install App' in the address bar or use the button below."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
title: "Offline Test",
|
||||
description: "Disable your internet connection and test password generation."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
title: "App Icon",
|
||||
description: "PassMaster appears as an app icon on your home screen or in the app list."
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="min-h-screen py-12">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{/* Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<div className="flex justify-center mb-6">
|
||||
<div className="p-4 bg-primary-100 dark:bg-primary-900/20 rounded-full">
|
||||
{isOnline ? (
|
||||
<Wifi className="h-12 w-12 text-primary-600" />
|
||||
) : (
|
||||
<WifiOff className="h-12 w-12 text-primary-600" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
Offline Password Generator (PWA)
|
||||
</h1>
|
||||
|
||||
<p className="text-xl text-gray-600 dark:text-gray-300 mb-6">
|
||||
Install and use PassMaster completely offline. Service Worker and local storage for maximum independence.
|
||||
</p>
|
||||
|
||||
{/* Connection Status */}
|
||||
<div className={`inline-flex items-center px-4 py-2 rounded-full text-sm font-medium ${
|
||||
isOnline
|
||||
? 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-300'
|
||||
: 'bg-orange-100 text-orange-800 dark:bg-orange-900/20 dark:text-orange-300'
|
||||
}`}>
|
||||
{isOnline ? (
|
||||
<>
|
||||
<CheckCircle className="h-4 w-4 mr-2" />
|
||||
Online - Ready for Installation
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<AlertCircle className="h-4 w-4 mr-2" />
|
||||
Offline Mode Active
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Install Button */}
|
||||
{isInstallable && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<button
|
||||
onClick={handleInstallClick}
|
||||
className="btn-primary text-lg px-8 py-4 inline-flex items-center space-x-2"
|
||||
>
|
||||
<Download className="h-5 w-5" />
|
||||
<span>Install PassMaster as App</span>
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Features */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="mb-16"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-8 text-center">
|
||||
Service Worker & Installation | FAQ | Security
|
||||
</h2>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{offlineFeatures.map((feature, index) => (
|
||||
<motion.div
|
||||
key={feature.title}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.1 }}
|
||||
className="card text-center"
|
||||
>
|
||||
<div className="flex justify-center mb-4">
|
||||
<div className="p-3 bg-primary-100 dark:bg-primary-900/20 rounded-full">
|
||||
<feature.icon className="h-8 w-8 text-primary-600" />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
{feature.description}
|
||||
</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Installation Steps */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
className="mb-16"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-8 text-center">
|
||||
PWA Installation in 3 Steps
|
||||
</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
{installSteps.map((step, index) => (
|
||||
<motion.div
|
||||
key={step.step}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.5 + index * 0.1 }}
|
||||
className="flex items-start space-x-4 card"
|
||||
>
|
||||
<div className="flex-shrink-0 w-8 h-8 bg-primary-600 text-white rounded-full flex items-center justify-center font-semibold">
|
||||
{step.step}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Platform Support */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.6 }}
|
||||
className="mb-16"
|
||||
>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-8 text-center">
|
||||
Platform Support
|
||||
</h2>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<div className="card text-center">
|
||||
<Monitor className="h-12 w-12 text-primary-600 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Desktop Browser
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Chrome, Firefox, Safari, Edge - All modern browsers support PWA installation
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="card text-center">
|
||||
<Smartphone className="h-12 w-12 text-primary-600 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Mobile Devices
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
iOS Safari, Android Chrome - Installation via "Add to Home Screen"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* FAQ Section */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.7 }}
|
||||
className="card"
|
||||
>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
Offline FAQ
|
||||
</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
How do I install PassMaster as a PWA?
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
On supported browsers, an installation icon automatically appears in the address bar.
|
||||
Alternatively, use the "Install App" button on this page.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
What offline features are available?
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
All main functions: password generation, parameter customization, entropy calculation,
|
||||
and copying to clipboard work completely offline.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
What is stored locally?
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Only app files (HTML, CSS, JavaScript) are stored in the browser cache.
|
||||
No passwords or personal data are ever stored.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* JSON-LD for FAQ */}
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "How do I install PassMaster as a PWA?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "On supported browsers, an installation icon automatically appears in the address bar. Alternatively, use the 'Install App' button."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What offline features are available?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "All main functions: password generation, parameter customization, entropy calculation, and copying work completely offline."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What is stored locally?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Only app files are stored in the browser cache. No passwords or personal data are ever stored."
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -43,8 +43,8 @@ export default function HomePage() {
|
||||
},
|
||||
{
|
||||
icon: Globe,
|
||||
title: "100% Open Source",
|
||||
description: "Transparent code that you can audit, modify, and contribute to on GitHub."
|
||||
title: "100% Privacy-First",
|
||||
description: "Transparent code that you can audit. No tracking, no data collection, no server communication."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function HomePage() {
|
||||
Free Offline Secure Password Generator
|
||||
</h1>
|
||||
<p className="text-xl md:text-2xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto leading-relaxed">
|
||||
Generate strong, unique passwords in seconds — fully client-side, private, and open-source.
|
||||
Generate strong, unique passwords in seconds — fully client-side, private, and secure.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
|
||||
@@ -29,11 +29,6 @@ export default function PrivacyPage() {
|
||||
title: "No Server Storage",
|
||||
description: "We don't store any passwords, user data, or personal information on our servers."
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Open Source",
|
||||
description: "All code is publicly available and auditable. You can verify our privacy claims."
|
||||
}
|
||||
]
|
||||
|
||||
const dataPractices = [
|
||||
@@ -227,10 +222,6 @@ export default function PrivacyPage() {
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>No Network Requests:</strong> The app works completely offline after initial load</span>
|
||||
</li>
|
||||
<li className="flex items-start space-x-3">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>Open Source:</strong> All code is publicly available on GitHub for verification</span>
|
||||
</li>
|
||||
<li className="flex items-start space-x-3">
|
||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
||||
<span><strong>No Dependencies:</strong> We don't use external services or third-party libraries that could track you</span>
|
||||
@@ -254,17 +245,9 @@ export default function PrivacyPage() {
|
||||
</h2>
|
||||
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
||||
We're committed to transparency. If you have any questions about our privacy practices,
|
||||
please review our source code or contact us.
|
||||
please contact us.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a
|
||||
href="https://github.com/your-repo/passmaster"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
View Source Code
|
||||
</a>
|
||||
<div className="flex justify-center">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-gray-300 dark:border-gray-600 text-base font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
|
||||
Reference in New Issue
Block a user