MVP fertig
This commit is contained in:
parent
bccaefedb3
commit
fc62302f97
|
|
@ -32,11 +32,6 @@ export default function ClientSidePage() {
|
||||||
title: "Zero Data Storage",
|
title: "Zero Data Storage",
|
||||||
description: "We don't store any passwords, user data, or personal information. Everything is processed locally and immediately discarded."
|
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 = [
|
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"
|
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" />
|
<ArrowLeft className="h-5 w-5 mr-2" />
|
||||||
Zurück zu PassMaster
|
Back to PassMaster
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -118,10 +113,10 @@ export default function ClientSidePage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||||
Client-Side Sicherheit
|
Client-Side Security
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
<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>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -135,14 +130,14 @@ export default function ClientSidePage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Sicherheits-Features
|
Security Features
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<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>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<div className="grid md:grid-cols-2 gap-8">
|
<div className="grid md:grid-cols-3 gap-8">
|
||||||
{securityFeatures.map((feature, index) => (
|
{securityFeatures.map((feature, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={feature.title}
|
key={feature.title}
|
||||||
|
|
@ -182,10 +177,10 @@ export default function ClientSidePage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Warum Client-Side Sicherheit?
|
Why Client-Side Security?
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||||
Die Vorteile der lokalen Passwort-Generierung.
|
The benefits of local password generation.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -225,10 +220,10 @@ export default function ClientSidePage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Technische Details
|
Technical Details
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||||
Wie PassMaster Ihre Sicherheit gewährleistet.
|
How PassMaster ensures your security.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -270,28 +265,24 @@ export default function ClientSidePage() {
|
||||||
<div className="flex items-center mb-6">
|
<div className="flex items-center mb-6">
|
||||||
<FileText className="h-8 w-8 text-green-600 mr-3" />
|
<FileText className="h-8 w-8 text-green-600 mr-3" />
|
||||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
||||||
Technische Implementierung
|
Technical Implementation
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="prose dark:prose-invert max-w-none">
|
<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">
|
<ul className="space-y-3 text-gray-600 dark:text-gray-300">
|
||||||
<li className="flex items-start space-x-3">
|
<li className="flex items-start space-x-3">
|
||||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
<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>
|
||||||
<li className="flex items-start space-x-3">
|
<li className="flex items-start space-x-3">
|
||||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
<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>
|
||||||
<li className="flex items-start space-x-3">
|
<li className="flex items-start space-x-3">
|
||||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
<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>
|
<span><strong>No Dependencies:</strong> We don't use external services or third-party libraries</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>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -308,26 +299,18 @@ export default function ClientSidePage() {
|
||||||
className="bg-green-50 dark:bg-green-900/20 rounded-lg p-8"
|
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">
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Fragen zur Sicherheit?
|
Questions About Security?
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
||||||
Wir sind verpflichtet zu Transparenz. Wenn Sie Fragen zu unseren Sicherheitspraktiken haben,
|
We are committed to transparency. If you have questions about our security practices,
|
||||||
überprüfen Sie unseren Quellcode oder kontaktieren Sie uns.
|
please contact us.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
<div className="flex 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>
|
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
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"
|
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>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -17,88 +17,88 @@ export default function ExcludeSimilarPage() {
|
||||||
const readabilityFeatures = [
|
const readabilityFeatures = [
|
||||||
{
|
{
|
||||||
icon: Eye,
|
icon: Eye,
|
||||||
title: "Ähnliche Zeichen ausschließen",
|
title: "Exclude Similar Characters",
|
||||||
description: "Verwirrende Zeichen wie 0/O, 1/l/I werden automatisch ausgeschlossen, um Lesbarkeit zu verbessern."
|
description: "Confusing characters like 0/O, 1/l/I are automatically excluded to improve readability."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: BookOpen,
|
icon: BookOpen,
|
||||||
title: "Bessere Lesbarkeit",
|
title: "Better Readability",
|
||||||
description: "Passwörter sind leichter zu lesen und zu tippen, ohne die Sicherheit zu beeinträchtigen."
|
description: "Passwords are easier to read and type without compromising security."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Target,
|
icon: Target,
|
||||||
title: "Weniger Fehler",
|
title: "Fewer Errors",
|
||||||
description: "Reduziert Tippfehler beim manuellen Eingeben von Passwörtern erheblich."
|
description: "Significantly reduces typing errors when manually entering passwords."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Users,
|
icon: Users,
|
||||||
title: "Benutzerfreundlich",
|
title: "User-Friendly",
|
||||||
description: "Besonders nützlich für ältere Benutzer oder bei der Eingabe auf mobilen Geräten."
|
description: "Especially useful for older users or when typing on mobile devices."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const excludedCharacters = [
|
const excludedCharacters = [
|
||||||
{
|
{
|
||||||
category: "Zahlen und Buchstaben",
|
category: "Numbers and Letters",
|
||||||
characters: ["0 (Null)", "O (Großes O)", "1 (Eins)", "l (kleines L)", "I (Großes i)"],
|
characters: ["0 (Zero)", "O (Capital O)", "1 (One)", "l (lowercase L)", "I (Capital I)"],
|
||||||
reason: "Diese Zeichen sehen in vielen Schriftarten identisch aus"
|
reason: "These characters look identical in many fonts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
category: "Sonderzeichen",
|
category: "Special Characters",
|
||||||
characters: ["| (Pipe)", "` (Backtick)", "' (Apostroph)", "\" (Anführungszeichen)"],
|
characters: ["| (Pipe)", "` (Backtick)", "' (Apostrophe)", "\" (Quotation marks)"],
|
||||||
reason: "Können in verschiedenen Kontexten verwirrend sein"
|
reason: "Can be confusing in different contexts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
category: "Leerzeichen",
|
category: "Spaces",
|
||||||
characters: [" (Leerzeichen)", " (Mehrfache Leerzeichen)"],
|
characters: [" (Space)", " (Multiple spaces)"],
|
||||||
reason: "Können beim Kopieren/Einfügen Probleme verursachen"
|
reason: "Can cause problems when copying/pasting"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const benefits = [
|
const benefits = [
|
||||||
{
|
{
|
||||||
icon: Zap,
|
icon: Zap,
|
||||||
title: "Schnellere Eingabe",
|
title: "Faster Input",
|
||||||
description: "Weniger Verwirrung beim manuellen Tippen von Passwörtern."
|
description: "Less confusion when manually typing passwords."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: CheckCircle,
|
icon: CheckCircle,
|
||||||
title: "Weniger Fehler",
|
title: "Fewer Errors",
|
||||||
description: "Reduziert Tippfehler und damit verbundene Frustration."
|
description: "Reduces typing errors and associated frustration."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Eye,
|
icon: Eye,
|
||||||
title: "Bessere UX",
|
title: "Better UX",
|
||||||
description: "Verbessert die Benutzererfahrung ohne Sicherheitsverlust."
|
description: "Improves user experience without security loss."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const securityImpact = [
|
const securityImpact = [
|
||||||
{
|
{
|
||||||
title: "Sicherheit bleibt hoch",
|
title: "Security Remains High",
|
||||||
items: [
|
items: [
|
||||||
"Entropie wird nur minimal reduziert",
|
"Entropy is only minimally reduced",
|
||||||
"Noch immer über 80 Zeichen verfügbar",
|
"Still over 80 characters available",
|
||||||
"Kryptographisch sichere Generierung",
|
"Cryptographically secure generation",
|
||||||
"Ausreichend für alle praktischen Zwecke"
|
"Sufficient for all practical purposes"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Praktische Vorteile",
|
title: "Practical Benefits",
|
||||||
items: [
|
items: [
|
||||||
"Einfachere manuelle Eingabe",
|
"Easier manual input",
|
||||||
"Weniger Support-Anfragen",
|
"Fewer support requests",
|
||||||
"Bessere Benutzerakzeptanz",
|
"Better user acceptance",
|
||||||
"Reduzierte Fehlerrate"
|
"Reduced error rate"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Empfohlene Verwendung",
|
title: "Recommended Usage",
|
||||||
items: [
|
items: [
|
||||||
"Für manuell eingegebene Passwörter",
|
"For manually entered passwords",
|
||||||
"Bei älteren Benutzern",
|
"For older users",
|
||||||
"Auf mobilen Geräten",
|
"On mobile devices",
|
||||||
"In Umgebungen mit schlechter Sichtbarkeit"
|
"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"
|
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" />
|
<ArrowLeft className="h-5 w-5 mr-2" />
|
||||||
Zurück zu PassMaster
|
Back to PassMaster
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -134,11 +134,11 @@ export default function ExcludeSimilarPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||||
Lesbarkeit & Benutzerfreundlichkeit
|
Readability & User-Friendliness
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
<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.
|
Improve the readability of your passwords without sacrificing security.
|
||||||
Ähnliche Zeichen werden automatisch ausgeschlossen.
|
Similar characters are automatically excluded.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -152,10 +152,10 @@ export default function ExcludeSimilarPage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Lesbarkeits-Features
|
Readability Features
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||||
Wie PassMaster die Benutzerfreundlichkeit verbessert.
|
How PassMaster improves user-friendliness.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -199,10 +199,10 @@ export default function ExcludeSimilarPage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Ausgeschlossene Zeichen
|
Excluded Characters
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<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>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -245,10 +245,10 @@ export default function ExcludeSimilarPage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Vorteile der Lesbarkeit
|
Benefits of Readability
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||||
Warum lesbare Passwörter wichtig sind.
|
Why readable passwords are important.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
@ -288,10 +288,10 @@ export default function ExcludeSimilarPage() {
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Sicherheit vs. Lesbarkeit
|
Security vs. Readability
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 dark:text-gray-300">
|
<p className="text-lg text-gray-600 dark:text-gray-300">
|
||||||
Wie wir das perfekte Gleichgewicht finden.
|
How we find the perfect balance.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</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"
|
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">
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-6 text-center">
|
||||||
Beispiel-Vergleich
|
Example Comparison
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className="grid md:grid-cols-2 gap-8">
|
<div className="grid md:grid-cols-2 gap-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
|
<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" />
|
<XCircle className="h-5 w-5 text-red-500 mr-2" />
|
||||||
Ohne Lesbarkeits-Filter
|
Without Readability Filter
|
||||||
</h3>
|
</h3>
|
||||||
<div className="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg font-mono text-sm">
|
<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>K9mP0lI|nQ2v</div>
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -352,13 +352,13 @@ export default function ExcludeSimilarPage() {
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
|
<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" />
|
<CheckCircle className="h-5 w-5 text-green-500 mr-2" />
|
||||||
Mit Lesbarkeits-Filter
|
With Readability Filter
|
||||||
</h3>
|
</h3>
|
||||||
<div className="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg font-mono text-sm">
|
<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>K9mP3nQ2vX7w</div>
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
<div className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||||
Keine verwirrenden Zeichen
|
No confusing characters
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -376,24 +376,24 @@ export default function ExcludeSimilarPage() {
|
||||||
className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-8"
|
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">
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
Bereit für bessere Lesbarkeit?
|
Ready for Better Readability?
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
||||||
Aktivieren Sie die Lesbarkeits-Option in PassMaster und generieren Sie
|
Enable the readability option in PassMaster and generate
|
||||||
benutzerfreundliche, aber dennoch sichere Passwörter.
|
user-friendly, yet secure passwords.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
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"
|
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>
|
||||||
<Link
|
<Link
|
||||||
href="/client-side"
|
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"
|
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>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -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,
|
icon: Globe,
|
||||||
title: "100% Open Source",
|
title: "100% Privacy-First",
|
||||||
description: "Transparent code that you can audit, modify, and contribute to on GitHub."
|
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
|
Free Offline Secure Password Generator
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl md:text-2xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto leading-relaxed">
|
<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>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,6 @@ export default function PrivacyPage() {
|
||||||
title: "No Server Storage",
|
title: "No Server Storage",
|
||||||
description: "We don't store any passwords, user data, or personal information on our servers."
|
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 = [
|
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" />
|
<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>
|
<span><strong>No Network Requests:</strong> The app works completely offline after initial load</span>
|
||||||
</li>
|
</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">
|
<li className="flex items-start space-x-3">
|
||||||
<CheckCircle className="h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" />
|
<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>
|
<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>
|
</h2>
|
||||||
<p className="text-gray-600 dark:text-gray-300 mb-6">
|
<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,
|
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>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
<div className="flex 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>
|
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
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"
|
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"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "PassMaster - Passwort Generator offline, DSGVO-konform",
|
"name": "PassMaster - Free Offline Secure Password Generator",
|
||||||
"short_name": "PassMaster",
|
"short_name": "PassMaster",
|
||||||
"description": "Sichere Passwörter generieren - 100% client-seitig, offline, DSGVO-konform, open-source. Web Crypto API für maximale Sicherheit.",
|
"description": "Generate secure passwords - 100% client-side, offline, GDPR-compliant, privacy-first. Web Crypto API for maximum security.",
|
||||||
"id": "passmaster-pwa",
|
"id": "passmaster-pwa",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
"theme_color": "#3b82f6",
|
"theme_color": "#3b82f6",
|
||||||
"orientation": "portrait-primary",
|
"orientation": "portrait-primary",
|
||||||
"scope": "/",
|
"scope": "/",
|
||||||
"lang": "de",
|
"lang": "en",
|
||||||
"categories": ["security", "utilities", "productivity", "developer-tools"],
|
"categories": ["security", "utilities", "productivity", "developer-tools"],
|
||||||
"prefer_related_applications": false,
|
"prefer_related_applications": false,
|
||||||
"related_applications": [],
|
"related_applications": [],
|
||||||
|
|
@ -68,9 +68,9 @@
|
||||||
],
|
],
|
||||||
"shortcuts": [
|
"shortcuts": [
|
||||||
{
|
{
|
||||||
"name": "Passwort generieren",
|
"name": "Generate Password",
|
||||||
"short_name": "Generieren",
|
"short_name": "Generate",
|
||||||
"description": "Schnell ein neues sicheres Passwort generieren",
|
"description": "Quickly generate a new secure password",
|
||||||
"url": "/#generator",
|
"url": "/#generator",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
|
|
@ -80,9 +80,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Offline nutzen",
|
"name": "Use Offline",
|
||||||
"short_name": "Offline",
|
"short_name": "Offline",
|
||||||
"description": "Passwörter ohne Internetverbindung generieren",
|
"description": "Generate passwords without internet connection",
|
||||||
"url": "/offline",
|
"url": "/offline",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
|
|
@ -92,9 +92,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Ähnliche Zeichen ausschließen",
|
"name": "Exclude Similar Characters",
|
||||||
"short_name": "Lesbarkeit",
|
"short_name": "Readability",
|
||||||
"description": "Passwörter ohne verwirrende ähnliche Zeichen",
|
"description": "Passwords without confusing similar characters",
|
||||||
"url": "/exclude-similar",
|
"url": "/exclude-similar",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import { Header } from '@/components/layout/Header'
|
||||||
import { Footer } from '@/components/layout/Footer'
|
import { Footer } from '@/components/layout/Footer'
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'PassMaster – Passwort Generator offline, open-source | DSGVO-konform',
|
title: 'PassMaster – Free Offline Secure Password Generator | Privacy-First',
|
||||||
description: 'Kostenlos, offline, client-side: Erstelle sichere Passwörter mit PassMaster. Transparent, DSGVO-konform, Open-Source für maximale Sicherheit.',
|
description: 'Free, offline, client-side: Generate secure passwords with PassMaster. Transparent, GDPR-compliant, privacy-first for maximum security.',
|
||||||
keywords: ['passwort generator', 'passwort generator offline', 'client-side password generator', 'open source password generator', 'exclude similar characters', 'password generator DSGVO', 'diceware vs random', 'passwort generator DACH', 'password length security', 'passwort generator open source', 'DSGVO', 'Web Crypto API', 'PWA', 'offline', 'client-seitig', 'Datenschutz', 'Sicherheit'],
|
keywords: ['password generator', 'password generator offline', 'client-side password generator', 'secure password generator', 'exclude similar characters', 'password generator GDPR', 'diceware vs random', 'password generator privacy', 'password length security', 'password generator secure', 'GDPR', 'Web Crypto API', 'PWA', 'offline', 'client-side', 'privacy', 'security'],
|
||||||
authors: [{ name: 'PassMaster' }],
|
authors: [{ name: 'PassMaster' }],
|
||||||
creator: 'PassMaster',
|
creator: 'PassMaster',
|
||||||
publisher: 'PassMaster',
|
publisher: 'PassMaster',
|
||||||
|
|
@ -36,8 +36,8 @@ export const metadata: Metadata = {
|
||||||
},
|
},
|
||||||
manifest: '/manifest.json',
|
manifest: '/manifest.json',
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: 'PassMaster – Passwort Generator offline, open-source | DSGVO-konform',
|
title: 'PassMaster – Free Offline Secure Password Generator | Privacy-First',
|
||||||
description: 'Kostenlos, offline, client-side: Erstelle sichere Passwörter mit PassMaster. Transparent, DSGVO-konform, Open-Source für maximale Sicherheit.',
|
description: 'Free, offline, client-side: Generate secure passwords with PassMaster. Transparent, GDPR-compliant, privacy-first for maximum security.',
|
||||||
url: '/',
|
url: '/',
|
||||||
siteName: 'PassMaster',
|
siteName: 'PassMaster',
|
||||||
images: [
|
images: [
|
||||||
|
|
@ -45,16 +45,16 @@ export const metadata: Metadata = {
|
||||||
url: '/og-image.png',
|
url: '/og-image.png',
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 630,
|
height: 630,
|
||||||
alt: 'PassMaster - Sicherer Passwort Generator',
|
alt: 'PassMaster - Secure Password Generator',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
locale: 'de_DE',
|
locale: 'en_US',
|
||||||
type: 'website',
|
type: 'website',
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: 'summary_large_image',
|
card: 'summary_large_image',
|
||||||
title: 'PassMaster – Passwort Generator offline, open-source',
|
title: 'PassMaster – Free Offline Secure Password Generator',
|
||||||
description: 'Kostenlos, offline, client-side: Erstelle sichere Passwörter mit PassMaster. Transparent, DSGVO-konform, Open-Source.',
|
description: 'Free, offline, client-side: Generate secure passwords with PassMaster. Transparent, GDPR-compliant, privacy-first.',
|
||||||
images: ['/og-image.png'],
|
images: ['/og-image.png'],
|
||||||
},
|
},
|
||||||
robots: {
|
robots: {
|
||||||
|
|
@ -126,18 +126,18 @@ export default function RootLayout({
|
||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "SoftwareApplication",
|
"@type": "SoftwareApplication",
|
||||||
"name": "PassMaster Passwort Generator",
|
"name": "PassMaster Password Generator",
|
||||||
"description": "100% client-seitiger, offline-fähiger, PWA Passwort Generator. Kostenlos, Open-Source, DSGVO-konform für maximale Sicherheit und Datenschutz.",
|
"description": "100% client-side, offline-capable, PWA password generator. Free, privacy-first, GDPR-compliant for maximum security and privacy.",
|
||||||
"applicationCategory": "SecurityApplication",
|
"applicationCategory": "SecurityApplication",
|
||||||
"operatingSystem": "Web, PWA",
|
"operatingSystem": "Web, PWA",
|
||||||
"featureList": [
|
"featureList": [
|
||||||
"Web Crypto API für kryptografische Sicherheit",
|
"Web Crypto API for cryptographic security",
|
||||||
"offline-fähig mit Service Worker",
|
"offline-capable with Service Worker",
|
||||||
"exclude similar characters Funktion",
|
"exclude similar characters function",
|
||||||
"open-source und auditierbar",
|
"transparent and auditable",
|
||||||
"keine Serverübertragung",
|
"no server transmission",
|
||||||
"DSGVO-konform",
|
"GDPR-compliant",
|
||||||
"Client-seitige Verschlüsselung",
|
"Client-side encryption",
|
||||||
"Progressive Web App (PWA)"
|
"Progressive Web App (PWA)"
|
||||||
],
|
],
|
||||||
"offers": {
|
"offers": {
|
||||||
|
|
@ -159,7 +159,7 @@ export default function RootLayout({
|
||||||
(process.env.NEXT_PUBLIC_SITE_URL || "https://passmaster.app") + "/screenshots/desktop.png",
|
(process.env.NEXT_PUBLIC_SITE_URL || "https://passmaster.app") + "/screenshots/desktop.png",
|
||||||
(process.env.NEXT_PUBLIC_SITE_URL || "https://passmaster.app") + "/screenshots/mobile.png"
|
(process.env.NEXT_PUBLIC_SITE_URL || "https://passmaster.app") + "/screenshots/mobile.png"
|
||||||
],
|
],
|
||||||
"keywords": "passwort generator, offline, client-side, DSGVO, Web Crypto API, PWA, open source, sicherheit, datenschutz"
|
"keywords": "password generator, offline, client-side, GDPR, Web Crypto API, PWA, privacy-first, security, privacy"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
|
|
@ -178,7 +178,7 @@ export default function RootLayout({
|
||||||
"contactType": "customer service"
|
"contactType": "customer service"
|
||||||
},
|
},
|
||||||
"foundingDate": "2024",
|
"foundingDate": "2024",
|
||||||
"description": "Open-Source Passwort Generator für maximale Sicherheit und Datenschutz"
|
"description": "Privacy-first password generator for maximum security and privacy"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
|
|
|
||||||
|
|
@ -11,40 +11,40 @@ interface FAQItem {
|
||||||
|
|
||||||
const faqData: FAQItem[] = [
|
const faqData: FAQItem[] = [
|
||||||
{
|
{
|
||||||
question: "Ist der Passwort Generator 100% client-seitig?",
|
question: "Is the password generator 100% client-side?",
|
||||||
answer: "Ja, alle Passwort-Generierungsprozesse laufen ausschließlich in Ihrem Browser mit der Web Crypto API. Keine Daten werden jemals an unsere Server übertragen. PassMaster verwendet window.crypto.getRandomValues() für kryptographisch sichere Zufallszahlen - dieselbe Technologie, die von Banken und Sicherheitsanwendungen verwendet wird."
|
answer: "Yes, all password generation processes run exclusively in your browser using the Web Crypto API. No data is ever sent to our servers. PassMaster uses window.crypto.getRandomValues() for cryptographically secure random numbers - the same technology used by banks and security applications."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Funktioniert der Generator offline als PWA?",
|
question: "Does the generator work offline as a PWA?",
|
||||||
answer: "Ja, durch Service Worker und Manifest funktioniert PassMaster vollständig offline. Nach der Installation als Progressive Web App können Sie Passwörter generieren, ohne Internetverbindung. Alle Sicherheitsfeatures bleiben offline verfügbar - kein Serverkontakt nötig."
|
answer: "Yes, through Service Worker and Manifest, PassMaster works completely offline. After installation as a Progressive Web App, you can generate passwords without an internet connection. All security features remain available offline - no server contact needed."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Kann man ähnliche Zeichen ausschließen?",
|
question: "Can similar characters be excluded?",
|
||||||
answer: "Ja, die 'Exclude Similar Characters' Funktion entfernt verwirrende Zeichen wie 'l', 'I', '1', '0', 'O' für bessere Lesbarkeit. Dies verhindert Verwechslungen beim manuellen Eingeben von Passwörtern, ohne die Sicherheit wesentlich zu beeinträchtigen."
|
answer: "Yes, the 'Exclude Similar Characters' function removes confusing characters like 'l', 'I', '1', '0', 'O' for better readability. This prevents confusion when manually entering passwords without significantly compromising security."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Entspricht der Generator DSGVO-Richtlinien?",
|
question: "Is the generator GDPR compliant?",
|
||||||
answer: "Ja, PassMaster ist vollständig DSGVO-konform. Es erfolgt keine Speicherung oder Übertragung von Daten. Alle Prozesse laufen lokal in Ihrem Browser ab. Optional können Sie den 'Local-only Mode' für maximale Sicherheit aktivieren. Keine Cookies, kein Tracking, keine Datenverarbeitung auf Servern."
|
answer: "Yes, PassMaster is fully GDPR compliant. No data storage or transmission occurs. All processes run locally in your browser. You can optionally activate 'Local-only Mode' for maximum security. No cookies, no tracking, no server-side data processing."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Wie wird die Sicherheit der Passwörter gewährleistet?",
|
question: "How is password security ensured?",
|
||||||
answer: "PassMaster verwendet ausschließlich window.crypto.getRandomValues() - niemals Math.random(). Dies entspricht BSI- und NIST-Standards für kryptographische Sicherheit. Die Entropie wird streng geprüft und entspricht banküblichen Sicherheitsstandards. Der Code ist vollständig auditierbar und open-source."
|
answer: "PassMaster uses exclusively window.crypto.getRandomValues() - never Math.random(). This meets BSI and NIST standards for cryptographic security. Entropy is strictly verified and meets banking-level security standards. The code is fully auditable and transparent."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Was bedeutet 'Web Crypto API' für die Sicherheit?",
|
question: "What does 'Web Crypto API' mean for security?",
|
||||||
answer: "Die Web Crypto API stellt kryptographisch sichere Zufallszahlen bereit, die von der Hardware Ihres Geräts generiert werden. Dies ist derselbe Standard, der von Finanzinstituten verwendet wird. Im Gegensatz zu Math.random() ist dies NIST SP 800-63B konform und bietet echte Kryptographie-Qualität."
|
answer: "The Web Crypto API provides cryptographically secure random numbers generated by your device's hardware. This is the same standard used by financial institutions. Unlike Math.random(), this is NIST SP 800-63B compliant and provides true cryptographic quality."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Wie kann ich die Sicherheit selbst überprüfen?",
|
question: "How can I verify the security myself?",
|
||||||
answer: "Der gesamte Code ist open-source und auf GitHub auditierbar. Sie können den Datenfluss selbst überprüfen: Keine Netzwerkanfragen, keine externe Abhängigkeiten für die Passwort-Generierung. Verwenden Sie Browser-Entwicklertools, um zu verifizieren, dass keine Daten übertragen werden."
|
answer: "The entire code is transparent and auditable. You can verify the data flow yourself: no network requests, no external dependencies for password generation. Use browser developer tools to verify that no data is transmitted."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Warum ist lokale Generierung sicherer als Online-Tools?",
|
question: "Why is local generation safer than online tools?",
|
||||||
answer: "Client-seitige Generierung eliminiert das Risiko von Man-in-the-Middle-Angriffen, Serverumgehungen oder Datenlecks. Ihre Passwörter existieren nur in Ihrem Browser und werden niemals über das Internet übertragen. Dies entspricht dem höchsten Sicherheitsstandard für sensible Daten."
|
answer: "Client-side generation eliminates the risk of man-in-the-middle attacks, server bypasses, or data leaks. Your passwords exist only in your browser and are never transmitted over the internet. This meets the highest security standard for sensitive data."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Unterstützt PassMaster Diceware-Passphrasen?",
|
question: "Does PassMaster support Diceware passphrases?",
|
||||||
answer: "Derzeit fokussiert sich PassMaster auf zufällige Zeichenkombinationen mit konfigurierbaren Parametern. Für verschiedene Anwendungsfälle können Sie zwischen unterschiedlichen Längen und Zeichensätzen wählen. Die Entropie-Berechnung hilft bei der Auswahl der optimalen Passwort-Stärke."
|
answer: "Currently, PassMaster focuses on random character combinations with configurable parameters. For different use cases, you can choose between different lengths and character sets. The entropy calculation helps in selecting the optimal password strength."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,10 @@ export function PasswordGenerator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStrengthLevel = (entropy: number) => {
|
const getStrengthLevel = (entropy: number) => {
|
||||||
if (entropy < 40) return { level: 'Schwach', color: 'strength-weak', bg: 'bg-red-500' }
|
if (entropy < 40) return { level: 'Weak', color: 'strength-weak', bg: 'bg-red-500' }
|
||||||
if (entropy < 60) return { level: 'Mittel', color: 'strength-ok', bg: 'bg-yellow-500' }
|
if (entropy < 60) return { level: 'Medium', color: 'strength-ok', bg: 'bg-yellow-500' }
|
||||||
if (entropy < 80) return { level: 'Stark', color: 'strength-strong', bg: 'bg-blue-500' }
|
if (entropy < 80) return { level: 'Strong', color: 'strength-strong', bg: 'bg-blue-500' }
|
||||||
return { level: 'Sehr Stark', color: 'strength-excellent', bg: 'bg-green-500' }
|
return { level: 'Very Strong', color: 'strength-excellent', bg: 'bg-green-500' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const entropy = password ? calculateEntropy(password) : 0
|
const entropy = password ? calculateEntropy(password) : 0
|
||||||
|
|
@ -120,7 +120,7 @@ export function PasswordGenerator() {
|
||||||
{/* Generated Password */}
|
{/* Generated Password */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Generiertes Passwort
|
Generated Password
|
||||||
</label>
|
</label>
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<div className="flex-1 relative">
|
<div className="flex-1 relative">
|
||||||
|
|
@ -129,13 +129,13 @@ export function PasswordGenerator() {
|
||||||
value={password}
|
value={password}
|
||||||
readOnly
|
readOnly
|
||||||
className="input-field font-mono text-lg"
|
className="input-field font-mono text-lg"
|
||||||
placeholder="Klicken Sie auf 'Passwort generieren' für ein sicheres Passwort"
|
placeholder="Click 'Generate Password' for a secure password"
|
||||||
aria-label="Generiertes Passwort"
|
aria-label="Generated Password"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition-colors duration-200"
|
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition-colors duration-200"
|
||||||
aria-label={showPassword ? 'Passwort verstecken' : 'Passwort anzeigen'}
|
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||||
>
|
>
|
||||||
{showPassword ? <EyeOff className="h-5 w-5" /> : <Eye className="h-5 w-5" />}
|
{showPassword ? <EyeOff className="h-5 w-5" /> : <Eye className="h-5 w-5" />}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -146,7 +146,7 @@ export function PasswordGenerator() {
|
||||||
className="px-4 py-3 bg-primary-600 text-white rounded-md hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-2 transition-colors duration-200"
|
className="px-4 py-3 bg-primary-600 text-white rounded-md hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-2 transition-colors duration-200"
|
||||||
whileHover={{ scale: password ? 1.05 : 1 }}
|
whileHover={{ scale: password ? 1.05 : 1 }}
|
||||||
whileTap={{ scale: password ? 0.95 : 1 }}
|
whileTap={{ scale: password ? 0.95 : 1 }}
|
||||||
aria-label="Passwort kopieren"
|
aria-label="Copy password"
|
||||||
>
|
>
|
||||||
<AnimatePresence mode="wait">
|
<AnimatePresence mode="wait">
|
||||||
{copied ? (
|
{copied ? (
|
||||||
|
|
@ -171,7 +171,7 @@ export function PasswordGenerator() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
<span>{copied ? 'Kopiert!' : 'Kopieren'}</span>
|
<span>{copied ? 'Copied!' : 'Copy'}</span>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -179,7 +179,7 @@ export function PasswordGenerator() {
|
||||||
{password && (
|
{password && (
|
||||||
<div className="mt-4 space-y-2">
|
<div className="mt-4 space-y-2">
|
||||||
<div className="flex items-center justify-between text-sm">
|
<div className="flex items-center justify-between text-sm">
|
||||||
<span className="text-gray-600 dark:text-gray-400">Stärke:</span>
|
<span className="text-gray-600 dark:text-gray-400">Strength:</span>
|
||||||
<span className={`font-medium ${strength.color.replace('strength-', 'text-')}`}>
|
<span className={`font-medium ${strength.color.replace('strength-', 'text-')}`}>
|
||||||
{strength.level}
|
{strength.level}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -194,7 +194,7 @@ export function PasswordGenerator() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between text-xs text-gray-500 dark:text-gray-400">
|
<div className="flex justify-between text-xs text-gray-500 dark:text-gray-400">
|
||||||
<span>Entropy: {entropy.toFixed(1)} bits</span>
|
<span>Entropy: {entropy.toFixed(1)} bits</span>
|
||||||
<span>Zeit zum Knacken: {timeToCrack}</span>
|
<span>Time to crack: {timeToCrack}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -205,7 +205,7 @@ export function PasswordGenerator() {
|
||||||
{/* Length Slider */}
|
{/* Length Slider */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Passwort-Länge: {options.length}
|
Password Length: {options.length}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
|
|
@ -224,12 +224,12 @@ export function PasswordGenerator() {
|
||||||
{/* Character Options */}
|
{/* Character Options */}
|
||||||
<div className="grid md:grid-cols-2 gap-4">
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300">Zeichentypen</h3>
|
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300">Character Types</h3>
|
||||||
{[
|
{[
|
||||||
{ key: 'includeUppercase', label: 'Großbuchstaben (A-Z)' },
|
{ key: 'includeUppercase', label: 'Uppercase letters (A-Z)' },
|
||||||
{ key: 'includeLowercase', label: 'Kleinbuchstaben (a-z)' },
|
{ key: 'includeLowercase', label: 'Lowercase letters (a-z)' },
|
||||||
{ key: 'includeNumbers', label: 'Zahlen (0-9)' },
|
{ key: 'includeNumbers', label: 'Numbers (0-9)' },
|
||||||
{ key: 'includeSymbols', label: 'Symbole (!@#$%^&*)' },
|
{ key: 'includeSymbols', label: 'Symbols (!@#$%^&*)' },
|
||||||
].map(({ key, label }) => (
|
].map(({ key, label }) => (
|
||||||
<label key={key} className="flex items-center space-x-2 cursor-pointer">
|
<label key={key} className="flex items-center space-x-2 cursor-pointer">
|
||||||
<input
|
<input
|
||||||
|
|
@ -244,7 +244,7 @@ export function PasswordGenerator() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300">Optionen</h3>
|
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300">Options</h3>
|
||||||
<label className="flex items-start space-x-2 cursor-pointer">
|
<label className="flex items-start space-x-2 cursor-pointer">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
@ -253,11 +253,11 @@ export function PasswordGenerator() {
|
||||||
className="rounded border-gray-300 text-primary-600 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 mt-0.5"
|
className="rounded border-gray-300 text-primary-600 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 mt-0.5"
|
||||||
/>
|
/>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">Ähnliche Zeichen ausschließen</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300">Exclude similar characters</span>
|
||||||
<div className="flex items-center space-x-1 mt-1">
|
<div className="flex items-center space-x-1 mt-1">
|
||||||
<Info className="h-3 w-3 text-gray-400" />
|
<Info className="h-3 w-3 text-gray-400" />
|
||||||
<span className="text-xs text-gray-500 dark:text-gray-400">
|
<span className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
Schließt 0/O, l/I, 1/I aus um Verwechslungen zu vermeiden
|
Excludes 0/O, l/I, 1/I to avoid confusion
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -274,12 +274,12 @@ export function PasswordGenerator() {
|
||||||
whileTap={{ scale: 0.98 }}
|
whileTap={{ scale: 0.98 }}
|
||||||
>
|
>
|
||||||
<RefreshCw className="h-5 w-5" />
|
<RefreshCw className="h-5 w-5" />
|
||||||
<span>Passwort generieren</span>
|
<span>Generate Password</span>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
|
|
||||||
{/* ARIA Live Region for Copy Feedback */}
|
{/* ARIA Live Region for Copy Feedback */}
|
||||||
<div aria-live="polite" className="sr-only">
|
<div aria-live="polite" className="sr-only">
|
||||||
{copied && 'Passwort in Zwischenablage kopiert'}
|
{copied && 'Password copied to clipboard'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ export function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer className="bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700">
|
<footer className="bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
{/* Brand */}
|
{/* Brand */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
|
@ -18,7 +18,7 @@ export function Footer() {
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600 dark:text-gray-400 max-w-xs">
|
<p className="text-sm text-gray-600 dark:text-gray-400 max-w-xs">
|
||||||
Generate ultra-secure passwords instantly, offline with client-side encryption.
|
Generate ultra-secure passwords instantly, offline with client-side encryption.
|
||||||
100% open-source, private, and free.
|
100% privacy-first, private, and free.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -63,26 +63,6 @@ export function Footer() {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Open Source */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white uppercase tracking-wider">
|
|
||||||
Open Source
|
|
||||||
</h3>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<a
|
|
||||||
href="https://github.com/your-username/passmaster"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="flex items-center space-x-2 text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors duration-200"
|
|
||||||
>
|
|
||||||
<Github className="h-4 w-4" />
|
|
||||||
<span>View on GitHub</span>
|
|
||||||
</a>
|
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500">
|
|
||||||
Licensed under MIT
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom Bar */}
|
{/* Bottom Bar */}
|
||||||
|
|
|
||||||
|
|
@ -92,19 +92,19 @@ export function Header() {
|
||||||
href="/client-side"
|
href="/client-side"
|
||||||
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors duration-200 px-3 py-2 rounded-md text-sm font-medium"
|
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors duration-200 px-3 py-2 rounded-md text-sm font-medium"
|
||||||
>
|
>
|
||||||
Sicherheit
|
Security
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/exclude-similar"
|
href="/exclude-similar"
|
||||||
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors duration-200 px-3 py-2 rounded-md text-sm font-medium"
|
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors duration-200 px-3 py-2 rounded-md text-sm font-medium"
|
||||||
>
|
>
|
||||||
Lesbarkeit
|
Readability
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/privacy"
|
href="/privacy"
|
||||||
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors duration-200 px-3 py-2 rounded-md text-sm font-medium"
|
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors duration-200 px-3 py-2 rounded-md text-sm font-medium"
|
||||||
>
|
>
|
||||||
Datenschutz
|
Privacy
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{showInstallPrompt && (
|
{showInstallPrompt && (
|
||||||
|
|
@ -116,7 +116,7 @@ export function Header() {
|
||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
<Download className="h-4 w-4" />
|
<Download className="h-4 w-4" />
|
||||||
<span>App installieren</span>
|
<span>Install App</span>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -163,21 +163,21 @@ export function Header() {
|
||||||
className="flex items-center justify-center px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
className="flex items-center justify-center px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
onClick={() => setMobileMenuOpen(false)}
|
||||||
>
|
>
|
||||||
Client-seitige Sicherheit
|
Client-Side Security
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/exclude-similar"
|
href="/exclude-similar"
|
||||||
className="flex items-center justify-center px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
className="flex items-center justify-center px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
onClick={() => setMobileMenuOpen(false)}
|
||||||
>
|
>
|
||||||
Ähnliche Zeichen
|
Similar Characters
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/privacy"
|
href="/privacy"
|
||||||
className="flex items-center justify-center px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
className="flex items-center justify-center px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
onClick={() => setMobileMenuOpen(false)}
|
||||||
>
|
>
|
||||||
Datenschutzerklärung
|
Privacy Policy
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{showInstallPrompt && (
|
{showInstallPrompt && (
|
||||||
|
|
@ -186,7 +186,7 @@ export function Header() {
|
||||||
className="btn-secondary flex items-center justify-center space-x-2"
|
className="btn-secondary flex items-center justify-center space-x-2"
|
||||||
>
|
>
|
||||||
<Download className="h-4 w-4" />
|
<Download className="h-4 w-4" />
|
||||||
<span>App installieren</span>
|
<span>Install App</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue