From 4a4388be64906a604a91c962a032ee37c836f7d6 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sat, 2 Aug 2025 02:02:51 +0200 Subject: [PATCH] Implementierung - SEO - 01.08.2025 --- .claude/settings.local.json | 3 +- dev-dist/sw.js | 2 +- dev-dist/sw.js.map | 2 +- index.html | 45 ++-- public/logo.svg | 16 ++ scripts/generate-icons.mjs | 4 +- src/App.tsx | 4 + src/components/FAQSection.tsx | 103 ++-------- src/components/FloatingPaths.tsx | 2 +- src/components/Footer.tsx | 4 +- src/components/GlobalBackground.tsx | 146 +++++++++++++ src/components/Layout.tsx | 17 +- src/components/PageTransition.tsx | 4 +- src/hooks/useScrollTracking.ts | 50 +++++ src/i18n/locales/de/faq.ts | 37 ++++ src/i18n/locales/de/index.ts | 5 + src/i18n/locales/en/faq.ts | 37 ++++ src/i18n/locales/en/index.ts | 5 + src/i18n/locales/sr/faq.ts | 37 ++++ src/i18n/locales/sr/index.ts | 5 + src/index.css | 37 +++- src/pages/about/components/Hero.tsx | 24 +-- src/pages/about/components/Skills.tsx | 2 +- src/pages/about/components/Workflow.tsx | 2 +- src/pages/blog/components/BlogPost.tsx | 42 +++- src/pages/blog/index.tsx | 6 +- src/pages/contact/components/ContactForm.tsx | 8 + src/pages/contact/index.tsx | 2 +- src/pages/home/components/About.tsx | 141 ++++++++----- src/pages/home/components/Experience.tsx | 94 ++++++--- src/pages/home/components/Hero.tsx | 34 ++- src/pages/home/components/Projects.tsx | 4 +- src/pages/home/components/Skills.tsx | 127 +++++++----- src/pages/home/index.tsx | 6 +- src/pages/portfolio/ProjectPage.tsx | 6 +- .../portfolio/components/PortfolioCard.tsx | 6 + .../portfolio/components/PortfolioGrid.tsx | 6 +- .../portfolio/components/ProjectLayout.tsx | 2 +- src/services/gtm.ts | 194 ++++++++++++++++++ src/styles/minimal-fixes.css | 1 - test-background.html | 139 +++++++++++++ vite.config.ts | 8 +- 42 files changed, 1098 insertions(+), 321 deletions(-) create mode 100644 public/logo.svg create mode 100644 src/components/GlobalBackground.tsx create mode 100644 src/hooks/useScrollTracking.ts create mode 100644 src/i18n/locales/de/faq.ts create mode 100644 src/i18n/locales/en/faq.ts create mode 100644 src/i18n/locales/sr/faq.ts create mode 100644 src/services/gtm.ts create mode 100644 test-background.html diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 2c65a36..6b29a01 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -15,7 +15,8 @@ "Bash(ls:*)", "Bash(pnpm add:*)", "Bash(pnpm approve-builds:*)", - "Bash(curl:*)" + "Bash(curl:*)", + "Bash(npx tailwindcss:*)" ], "deny": [] } diff --git a/dev-dist/sw.js b/dev-dist/sw.js index 6607700..d37fe07 100644 --- a/dev-dist/sw.js +++ b/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-be0f3d84'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.8k8mhvbe2f8" + "revision": "0.2p1auafpcng" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/dev-dist/sw.js.map b/dev-dist/sw.js.map index 0ec32cd..a891974 100644 --- a/dev-dist/sw.js.map +++ b/dev-dist/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../AppData/Local/Temp/f75120a193856f89e3955a00fcf118a2/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheableResponsePlugin as workbox_cacheable_response_CacheableResponsePlugin} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-cacheable-response@7.3.0/node_modules/workbox-cacheable-response/CacheableResponsePlugin.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-core@7.3.0/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"3ca0b8505b4bec776b69afdba2768812\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"0.8k8mhvbe2f8\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\"), {\n allowlist: [/^\\/$/],\n \n}));\n\n\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.googleapis\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"google-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.gstatic\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"gstatic-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/www\\.googletagmanager\\.com\\/.*/i, new workbox_strategies_NetworkOnly(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","workbox_precaching_cleanupOutdatedCaches","workbox_routing_registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","allowlist","workbox_strategies_CacheFirst","plugins","workbox_cacheable_response_CacheableResponsePlugin","statuses","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../AppData/Local/Temp/86afd5ee57fa8d41fbf7c534a5f35a57/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheableResponsePlugin as workbox_cacheable_response_CacheableResponsePlugin} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-cacheable-response@7.3.0/node_modules/workbox-cacheable-response/CacheableResponsePlugin.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-strategies@7.3.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-core@7.3.0/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-routing@7.3.0/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/damja/WebstormProjects/Portfolio/node_modules/.pnpm/workbox-precaching@7.3.0/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"3ca0b8505b4bec776b69afdba2768812\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"0.2p1auafpcng\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\"), {\n allowlist: [/^\\/$/],\n \n}));\n\n\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.googleapis\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"google-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/fonts\\.gstatic\\.com\\/.*/i, new workbox_strategies_CacheFirst({ \"cacheName\":\"gstatic-fonts-cache\", plugins: [new workbox_cacheable_response_CacheableResponsePlugin({ statuses: [ 0, 200 ] })] }), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/www\\.googletagmanager\\.com\\/.*/i, new workbox_strategies_NetworkOnly(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","workbox_precaching_cleanupOutdatedCaches","workbox_routing_registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","allowlist","workbox_strategies_CacheFirst","plugins","workbox_cacheable_response_CacheableResponsePlugin","statuses","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file diff --git a/index.html b/index.html index 43a6d50..585948d 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,28 @@ - + - + + + + + + + + + + + + Damjan Savić - Fullstack Entwickler | Python, JavaScript, KI @@ -23,8 +38,13 @@ + + + + + @@ -41,7 +61,7 @@ html, body { - background-color: #18181B !important; + background-color: transparent; } /* Prevent initial flicker */ @@ -101,20 +121,15 @@ - - - - - + - -
+ + + + +
\ No newline at end of file diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..0313f9e --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/generate-icons.mjs b/scripts/generate-icons.mjs index bb10b84..d61c147 100644 --- a/scripts/generate-icons.mjs +++ b/scripts/generate-icons.mjs @@ -7,13 +7,13 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const PUBLIC_DIR = path.join(__dirname, '..', 'public'); -const SOURCE_IMAGE = path.join(PUBLIC_DIR, 'logo.png'); +const SOURCE_IMAGE = path.join(PUBLIC_DIR, 'logo.svg'); async function generateIcons() { try { // Check if source image exists if (!fs.existsSync(SOURCE_IMAGE)) { - console.error('Source logo.png not found in public directory'); + console.error('Source logo.svg not found in public directory'); // Create placeholder icons const svg = ` diff --git a/src/App.tsx b/src/App.tsx index f28fa4e..527b65f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,11 +10,15 @@ import PageTransition from './components/PageTransition'; import { ScrollProvider } from './components/ScrollContext'; import DebugOverlay from './components/DebugOverlay'; import { logPageView, isCookieCategoryEnabled } from './utils/analytics'; +import { useScrollTracking } from './hooks/useScrollTracking'; import './styles/scrollbar.css'; // RouteTracker Component für präzises Seiten-Tracking - aber nur mit Zustimmung const RouteTracker = () => { const location = useLocation(); + + // Scroll tracking aktivieren + useScrollTracking(); useEffect(() => { // Nur tracken, wenn die Analytics-Cookies akzeptiert wurden diff --git a/src/components/FAQSection.tsx b/src/components/FAQSection.tsx index f07c5ab..83ceeac 100644 --- a/src/components/FAQSection.tsx +++ b/src/components/FAQSection.tsx @@ -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([]); + const { t } = useTranslation(); + const [openItem, setOpenItem] = useState(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() { />

- {t('faq.title', 'Frequently Asked Questions')} + {t('faq.title')}

@@ -117,13 +56,13 @@ export function FAQSection() {