Implementierung - SEO - 01.08.2025

This commit is contained in:
2025-08-02 02:02:51 +02:00
parent e69e68242c
commit 4a4388be64
42 changed files with 1098 additions and 321 deletions
+21 -82
View File
@@ -1,87 +1,26 @@
import React, { useState } from 'react';
import { ChevronDown, ChevronUp } from 'lucide-react';
import { useTranslation } from 'react-i18next';
interface FAQItem {
question: string;
answer: string;
category?: string;
}
import { trackFAQInteraction } from '../services/gtm';
export function FAQSection() {
const { t, i18n } = useTranslation();
const [openItems, setOpenItems] = useState<number[]>([]);
const { t } = useTranslation();
const [openItem, setOpenItem] = useState<number | null>(null);
const faqs: FAQItem[] = i18n.language === 'de' ? [
{
question: "Wie kann ich Python für Prozessautomatisierung einsetzen?",
answer: "Python eignet sich hervorragend für Prozessautomatisierung durch Libraries wie Selenium für Web-Automation, Pandas für Datenverarbeitung und Schedule für zeitgesteuerte Aufgaben. Ich entwickle maßgeschneiderte Automatisierungslösungen für Ihre Geschäftsprozesse.",
category: "python"
},
{
question: "Was macht OLLAMA ideal für lokale KI-Entwicklung?",
answer: "OLLAMA ermöglicht das Ausführen großer Sprachmodelle lokal, was Datenschutz gewährleistet und API-Kosten reduziert. Ich spezialisiere mich auf die Integration von OLLAMA in Anwendungen für individuelle KI-Lösungen ohne Cloud-Abhängigkeiten.",
category: "ai"
},
{
question: "Welche Vorteile bieten Electron Desktop Apps?",
answer: "Electron ermöglicht die Entwicklung plattformübergreifender Desktop-Anwendungen mit Web-Technologien. Sie erhalten eine native App für Windows, Mac und Linux aus einer einzigen Codebasis. Ideal für Tools mit komplexer UI und Offline-Funktionalität.",
category: "electron"
},
{
question: "Wie lange dauert die Entwicklung einer Web-Anwendung?",
answer: "Die Entwicklungsdauer hängt vom Umfang ab. Ein MVP kann in 4-8 Wochen entwickelt werden, während komplexe Enterprise-Anwendungen 3-6 Monate benötigen. Ich arbeite agil und liefere in 2-Wochen-Sprints nutzbare Zwischenergebnisse.",
category: "general"
},
{
question: "Können Sie bestehende Python-Skripte in Web-Apps umwandeln?",
answer: "Ja, ich kann Ihre Python-Skripte in moderne Web-Anwendungen mit FastAPI oder Django Backend und React Frontend transformieren. Dies ermöglicht Multi-User-Zugriff, bessere UI/UX und zentrale Datenverwaltung.",
category: "python"
},
{
question: "Wie integrieren Sie KI in bestehende Geschäftsprozesse?",
answer: "Ich analysiere Ihre Workflows und identifiziere Automatisierungspotenziale. Mit OLLAMA oder anderen KI-Modellen entwickle ich Lösungen für Textanalyse, Dokumentenverarbeitung, Kundenservice-Automation oder Datenextraktion - alles datenschutzkonform on-premise.",
category: "ai"
}
] : [
{
question: "How can I use Python for process automation?",
answer: "Python excels at process automation through libraries like Selenium for web automation, Pandas for data processing, and Schedule for timed tasks. I develop custom automation solutions tailored to your business processes.",
category: "python"
},
{
question: "What makes OLLAMA ideal for local AI development?",
answer: "OLLAMA enables running large language models locally, ensuring data privacy and reducing API costs. I specialize in integrating OLLAMA into applications for custom AI solutions without cloud dependencies.",
category: "ai"
},
{
question: "What are the advantages of Electron desktop apps?",
answer: "Electron enables cross-platform desktop app development using web technologies. You get a native app for Windows, Mac, and Linux from a single codebase. Ideal for tools requiring complex UI and offline functionality.",
category: "electron"
},
{
question: "How long does web application development take?",
answer: "Development time depends on scope. An MVP can be developed in 4-8 weeks, while complex enterprise applications require 3-6 months. I work agile and deliver usable results in 2-week sprints.",
category: "general"
},
{
question: "Can you convert existing Python scripts into web apps?",
answer: "Yes, I can transform your Python scripts into modern web applications with FastAPI or Django backend and React frontend. This enables multi-user access, better UI/UX, and centralized data management.",
category: "python"
},
{
question: "How do you integrate AI into existing business processes?",
answer: "I analyze your workflows and identify automation potential. Using OLLAMA or other AI models, I develop solutions for text analysis, document processing, customer service automation, or data extraction - all privacy-compliant on-premise.",
category: "ai"
}
];
const faqs = t('faq.questions', { returnObjects: true }) as Array<{
question: string;
answer: string;
category?: string;
}>;
const toggleItem = (index: number) => {
setOpenItems(prev =>
prev.includes(index)
? prev.filter(i => i !== index)
: [...prev, index]
);
const isOpening = openItem !== index;
const question = faqs[index]?.question || '';
// Track FAQ interaction
trackFAQInteraction(question, isOpening ? 'open' : 'close');
setOpenItem(prev => prev === index ? null : index);
};
const faqSchema = {
@@ -105,7 +44,7 @@ export function FAQSection() {
/>
<h2 className="text-3xl font-bold text-white mb-8 text-center">
{t('faq.title', 'Frequently Asked Questions')}
{t('faq.title')}
</h2>
<div className="space-y-4">
@@ -117,13 +56,13 @@ export function FAQSection() {
<button
onClick={() => toggleItem(index)}
className="w-full px-6 py-4 text-left flex items-center justify-between hover:bg-zinc-800/70 transition-colors"
aria-expanded={openItems.includes(index)}
aria-expanded={openItem === index}
aria-controls={`faq-answer-${index}`}
>
<h3 className="text-lg font-medium text-white pr-4">
{faq.question}
</h3>
{openItems.includes(index) ? (
{openItem === index ? (
<ChevronUp className="h-5 w-5 text-zinc-400 flex-shrink-0" />
) : (
<ChevronDown className="h-5 w-5 text-zinc-400 flex-shrink-0" />
@@ -133,7 +72,7 @@ export function FAQSection() {
<div
id={`faq-answer-${index}`}
className={`overflow-hidden transition-all duration-300 ${
openItems.includes(index) ? 'max-h-96' : 'max-h-0'
openItem === index ? 'max-h-96' : 'max-h-0'
}`}
>
<div className="px-6 py-4 text-zinc-300 border-t border-zinc-700">
@@ -146,12 +85,12 @@ export function FAQSection() {
<div className="mt-8 text-center">
<p className="text-zinc-400">
{t('faq.moreQuestions', 'Have more questions?')}{' '}
{t('faq.moreQuestions')}{' '}
<a
href="/contact"
className="text-white hover:text-zinc-300 underline transition-colors"
>
{t('faq.contactUs', 'Contact us')}
{t('faq.contactUs')}
</a>
</p>
</div>
+1 -1
View File
@@ -15,7 +15,7 @@ export function FloatingPaths({ position }: { position: number }) {
}))
return (
<div className="absolute inset-0 pointer-events-none floating-paths" style={{ isolation: 'isolate', zIndex: 0 }}>
<div className="absolute inset-0 pointer-events-none floating-paths">
<svg className="w-full h-full text-accent" viewBox="0 0 696 316" fill="none" style={{ transform: 'translateZ(0)' }}>
<title>Background Paths</title>
{paths.map((path) => (
+2 -2
View File
@@ -8,7 +8,7 @@ const Footer = () => {
const currentYear = new Date().getFullYear();
return (
<footer className="relative bg-zinc-900 pt-8 pb-4 px-4">
<footer className="relative bg-zinc-800/50 backdrop-blur-sm border-t border-zinc-700/30 pt-8 pb-4 px-4">
<div className="max-w-7xl mx-auto">
<div className="flex flex-col space-y-8">
{/* Contact Section */}
@@ -93,7 +93,7 @@ const Footer = () => {
</div>
{/* Legal Section */}
<div className="border-t border-zinc-800 pt-4">
<div className="border-t border-zinc-700/30 pt-4">
<div className="flex flex-col space-y-4">
<p className="text-zinc-400 text-xs text-center">
&copy; {currentYear} Damjan Savić. {t('footer.legal.copyright')}
+146
View File
@@ -0,0 +1,146 @@
import { useEffect, useState } from 'react';
import { FloatingPaths } from './FloatingPaths';
const GlobalBackground = () => {
const [scrollPosition, setScrollPosition] = useState(0);
useEffect(() => {
const handleScroll = () => {
setScrollPosition(window.scrollY * 0.001);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<>
{/* Background layer - behind everything */}
<div
className="fixed inset-0 bg-zinc-900"
style={{
zIndex: -2,
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
width: '100%',
height: '100%'
}}
/>
{/* Gradient overlay */}
<div
className="fixed inset-0"
style={{
zIndex: -1,
background: 'linear-gradient(135deg, #1e1e1e 0%, #2a2a2a 50%, #1e1e1e 100%)',
opacity: 0.9
}}
/>
{/* FloatingPaths layer */}
<div
className="fixed inset-0"
style={{
zIndex: -1,
pointerEvents: 'none'
}}
>
<FloatingPaths position={scrollPosition} />
</div>
{/* Test: Visible animated lines */}
<div
className="fixed inset-0 pointer-events-none"
style={{ zIndex: -1 }}
>
<svg
className="w-full h-full"
preserveAspectRatio="none"
style={{ opacity: 0.3 }}
>
<line
x1="0%"
y1="20%"
x2="100%"
y2="20%"
stroke="white"
strokeWidth="1"
opacity="0.2"
>
<animate
attributeName="y1"
values="20%;80%;20%"
dur="10s"
repeatCount="indefinite"
/>
<animate
attributeName="y2"
values="20%;80%;20%"
dur="10s"
repeatCount="indefinite"
/>
</line>
<line
x1="0%"
y1="50%"
x2="100%"
y2="50%"
stroke="white"
strokeWidth="1"
opacity="0.15"
>
<animate
attributeName="x1"
values="0%;100%;0%"
dur="15s"
repeatCount="indefinite"
/>
</line>
<line
x1="20%"
y1="0%"
x2="20%"
y2="100%"
stroke="white"
strokeWidth="1"
opacity="0.1"
>
<animate
attributeName="x1"
values="20%;80%;20%"
dur="12s"
repeatCount="indefinite"
/>
<animate
attributeName="x2"
values="20%;80%;20%"
dur="12s"
repeatCount="indefinite"
/>
</line>
</svg>
</div>
{/* Grid overlay */}
<div
className="fixed inset-0 pointer-events-none"
style={{
zIndex: -1,
backgroundImage: `
linear-gradient(rgba(255,255,255,.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.05) 1px, transparent 1px)
`,
backgroundSize: '50px 50px',
opacity: 0.5
}}
/>
</>
);
};
export default GlobalBackground;
+11 -6
View File
@@ -20,6 +20,7 @@ import { Link, useLocation } from "react-router-dom";
import Footer from "./Footer";
import { useScrollContext } from "./ScrollContext";
import { PerformanceMonitor } from "./PerformanceMonitor";
import GlobalBackground from "./GlobalBackground";
interface LayoutProps {
children: ReactNode;
@@ -122,21 +123,25 @@ const Layout = ({ children }: LayoutProps) => {
// Render with opacity 0 on initial mount to prevent flicker
if (!isMounted) {
return (
<div className="min-h-screen bg-zinc-900">
<div className="min-h-screen bg-transparent">
<GlobalBackground />
{children}
</div>
);
}
return (
<div className="min-h-screen bg-zinc-900 flex flex-col relative">
<div className="min-h-screen flex flex-col relative">
{/* Global Background */}
<GlobalBackground />
{/* Navigation oberste Ebene */}
<nav
className={`
fixed w-full z-40 transition-all duration-300
bg-zinc-800/50 backdrop-blur-sm border-b border-zinc-700/30
${scrolled
? "bg-zinc-900/80 backdrop-blur-md shadow-lg shadow-zinc-900/50"
? "bg-zinc-800/70 backdrop-blur-md shadow-lg shadow-zinc-900/30"
: ""
}
`}
@@ -148,7 +153,7 @@ const Layout = ({ children }: LayoutProps) => {
{/* Logo */}
<Link to="/" className="flex items-center space-x-2 group shrink-0">
<motion.img
src="/logo.png"
src="/logo.svg"
alt=""
className="h-8 w-auto"
whileHover={{ scale: 1.05 }}
@@ -206,7 +211,7 @@ const Layout = ({ children }: LayoutProps) => {
animate={{ x: 0 }}
exit={{ x: "100%" }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
className="fixed right-0 top-0 h-full w-80 bg-zinc-900 shadow-xl md:hidden z-50 border-l border-zinc-800"
className="fixed right-0 top-0 h-full w-80 bg-zinc-900/95 backdrop-blur-md shadow-xl md:hidden z-50 border-l border-zinc-800"
>
{/* Sidebar Header mit Close-Button */}
<div className="flex items-center justify-between px-4 h-16 border-b border-zinc-800">
@@ -258,7 +263,7 @@ const Layout = ({ children }: LayoutProps) => {
</AnimatePresence>
{/* Hauptinhalt */}
<main className="flex-1 pt-2 relative z-30">{children}</main>
<main className="flex-1 pt-2 relative z-10 bg-transparent">{children}</main>
{/* Footer */}
<Footer />
+2 -2
View File
@@ -28,7 +28,7 @@ const Logo = () => {
>
{!imageError ? (
<img
src="/logo.png"
src="/logo.svg"
alt="Logo"
className="w-full h-full object-contain filter brightness-200"
onError={() => setImageError(true)}
@@ -123,7 +123,7 @@ const PageTransition = ({ children }: PageTransitionProps) => {
{isTransitioning && (
<motion.div
key="transition-overlay"
className="fixed inset-0 bg-zinc-900 flex items-center justify-center page-transition-active"
className="fixed inset-0 bg-zinc-900/95 backdrop-blur-sm flex items-center justify-center page-transition-active"
style={{ zIndex: 9999 }}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}