From b6ad1e0b2f654b43b402cf0247f163710dc40790 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Wed, 10 Jun 2026 23:56:36 +0200 Subject: [PATCH] chore: capture live server state before migration (2026-06-10) --- .npmrc | 1 + README.md | 2 +- package.json | 10 ++ playwright.config.ts | 18 +-- pnpm-lock.yaml | 11 +- pnpm-workspace.yaml | 6 + public/favicon.svg | 22 ++-- src/app/[locale]/about/page.tsx | 8 +- src/app/[locale]/blog/[slug]/page.tsx | 14 +-- src/app/[locale]/blog/page.tsx | 72 ++++++------ src/app/[locale]/imprint/page.tsx | 42 +++---- src/app/[locale]/layout.tsx | 2 +- src/app/[locale]/leistungen/[slug]/page.tsx | 56 ++++----- src/app/[locale]/leistungen/page.tsx | 86 +++++++------- .../leistungen/standort/[city]/page.tsx | 62 +++++----- .../leistungen/technologie/[tech]/page.tsx | 74 ++++++------ src/app/[locale]/portfolio/[slug]/page.tsx | 68 +++++------ src/app/[locale]/portfolio/page.tsx | 2 +- src/app/[locale]/privacy/page.tsx | 108 +++++++++--------- src/app/[locale]/terms/page.tsx | 26 ++--- src/app/icon.svg | 8 +- src/app/not-found.tsx | 6 +- src/components/about/Hero.tsx | 30 ++--- src/components/about/Journey.tsx | 48 ++++---- src/components/about/Skills.tsx | 20 ++-- src/components/about/Workflow.tsx | 8 +- src/components/auth/DashboardContent.tsx | 30 ++--- src/components/auth/LoginForm.tsx | 8 +- src/components/blog/BlogList.tsx | 66 +++++------ src/components/blog/CategoryFilter.tsx | 12 +- src/components/blog/SearchBar.tsx | 6 +- src/components/chat/ChatMessage.tsx | 32 +++--- src/components/chat/Chatbot.tsx | 30 ++--- src/components/contact/ContactForm.tsx | 60 +++++----- src/components/layout/ContactInfo.tsx | 14 +-- src/components/layout/Footer.tsx | 38 +++--- src/components/layout/GlobalBackground.tsx | 14 +-- src/components/layout/Header.tsx | 20 ++-- src/components/layout/LanguageSwitcher.tsx | 14 +-- src/components/layout/NavLink.tsx | 4 +- src/components/portfolio/CategoryFilter.tsx | 8 +- src/components/portfolio/PortfolioCard.tsx | 36 +++--- src/components/sections/About.tsx | 18 +-- src/components/sections/Experience.tsx | 21 ++-- src/components/sections/Hero.tsx | 32 +++--- src/components/sections/Projects.tsx | 32 +++--- src/components/sections/Skills.tsx | 26 ++--- src/lib/markdown.tsx | 38 +++--- src/messages/de.json | 8 +- src/messages/en.json | 8 +- src/messages/sr.json | 8 +- src/utils/constants.ts | 2 +- 52 files changed, 704 insertions(+), 691 deletions(-) create mode 100644 .npmrc create mode 100644 pnpm-workspace.yaml diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..a2dcee4 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +manage-package-manager-versions=false diff --git a/README.md b/README.md index d3ad505..ac42b03 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Personal portfolio website showcasing my work as an **AI & Automation Specialist ## Current Role -**Process Automation Specialist** @ Everlast Consulting GmbH (since Dec 2024) +**Process Automation Specialist** @ Everlast Consulting GmbH (since Dec 2025) - Developing AI agents with n8n and Zapier - Building web scraping solutions - Migration from Power Automate to n8n diff --git a/package.json b/package.json index e1a7da4..9e04985 100644 --- a/package.json +++ b/package.json @@ -65,5 +65,15 @@ "tailwindcss": "^4.1.0", "typescript": "5.9.3", "vitest": "^1.3.1" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "@parcel/watcher", + "@swc/core", + "esbuild", + "sharp", + "unrs-resolver" + ], + "ignoredBuiltDependencies": [] } } diff --git a/playwright.config.ts b/playwright.config.ts index 5c1f770..1769932 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -35,8 +35,8 @@ export default defineConfig({ // Shared settings for all projects use: { - // Base URL - uses dedicated test port to avoid conflicts with other dev servers - baseURL: 'http://localhost:3100', + // Base URL - test against running Docker container + baseURL: process.env.BASE_URL || 'http://localhost:3001', // Collect trace when retrying the failed test trace: 'on-first-retry', @@ -71,13 +71,13 @@ export default defineConfig({ }, ], - // Configure web server to start before tests on a dedicated port - webServer: { - command: 'pnpm dev --port 3100', - url: 'http://localhost:3100', - reuseExistingServer: false, - timeout: 120000, - }, + // Use running Docker container - no webServer needed + // webServer: { + // command: 'pnpm dev --port 3100', + // url: 'http://localhost:3100', + // reuseExistingServer: false, + // timeout: 120000, + // }, // Global timeout for each test timeout: 60000, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db37da1..51f8507 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2105,6 +2105,7 @@ packages: basic-ftp@5.1.0: resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} engines: {node: '>=10.0.0'} + deprecated: Security vulnerability fixed in 5.2.1, please upgrade bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -4366,8 +4367,8 @@ packages: third-party-web@0.27.0: resolution: {integrity: sha512-h0JYX+dO2Zr3abCQpS6/uFjujaOjA1DyDzGQ41+oFn9VW/ARiq9g5ln7qEP9+BTzDpOMyIfsfj4OvfgXAsMUSA==} - third-party-web@0.29.0: - resolution: {integrity: sha512-nBDSJw5B7Sl1YfsATG2XkW5qgUPODbJhXw++BKygi9w6O/NKS98/uY/nR/DxDq2axEjL6halHW1v+jhm/j1DBQ==} + third-party-web@0.29.2: + resolution: {integrity: sha512-fegtha91tq2DHphyoiBXVHjVi2YG9zFaRnboT9C28tO1en9Y3wJsfspuy40F+u5wl3hHVbw7cnd1b67kEGHb8g==} tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -5798,7 +5799,7 @@ snapshots: '@paulirish/trace_engine@0.0.61': dependencies: legacy-javascript: 0.0.1 - third-party-web: 0.29.0 + third-party-web: 0.29.2 '@playwright/test@1.58.0': dependencies: @@ -6136,7 +6137,7 @@ snapshots: '@testing-library/dom@9.3.4': dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 '@babel/runtime': 7.28.6 '@types/aria-query': 5.0.4 aria-query: 5.1.3 @@ -9606,7 +9607,7 @@ snapshots: third-party-web@0.27.0: {} - third-party-web@0.29.0: {} + third-party-web@0.29.2: {} tinybench@2.9.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..40efa4b --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,6 @@ +ignoredBuiltDependencies: + - '@parcel/watcher' + - '@swc/core' + - esbuild + - sharp + - unrs-resolver diff --git a/public/favicon.svg b/public/favicon.svg index 858beba..44bc1a1 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1,16 +1,8 @@ - - - - - - - - - - + + + + + + - \ No newline at end of file + diff --git a/src/app/[locale]/about/page.tsx b/src/app/[locale]/about/page.tsx index 077a173..1416b03 100644 --- a/src/app/[locale]/about/page.tsx +++ b/src/app/[locale]/about/page.tsx @@ -121,10 +121,10 @@ export default async function AboutPage({ params }: Props) {
-

+

{t('skills.title')}

-

+

{t('skills.description')}

@@ -136,10 +136,10 @@ export default async function AboutPage({ params }: Props) {
-

+

{t('workflow.title')}

-

+

{t('workflow.description')}

diff --git a/src/app/[locale]/blog/[slug]/page.tsx b/src/app/[locale]/blog/[slug]/page.tsx index 17ede0e..5b77fc9 100644 --- a/src/app/[locale]/blog/[slug]/page.tsx +++ b/src/app/[locale]/blog/[slug]/page.tsx @@ -1335,7 +1335,7 @@ export default async function BlogPostPage({ params }: Props) { {/* Back Link */} @@ -1345,22 +1345,22 @@ export default async function BlogPostPage({ params }: Props) { {/* Header */}
-
+
{readingTime} min read
- + {post.category}
-

+

{post.title}

-

+

{post.excerpt}

@@ -1369,7 +1369,7 @@ export default async function BlogPostPage({ params }: Props) { {post.tags?.map((tag, index) => ( {tag} @@ -1378,7 +1378,7 @@ export default async function BlogPostPage({ params }: Props) { {/* Cover Image */} -
+
{post.title}
{/* Image Container */} -
+
-
+
{/* Content */} -
-
+
+
{getFormattedDate(post.date, locale)} @@ -167,12 +167,12 @@ function BlogPostCard({ post, locale }: { post: BlogPost; locale: string }) { )}
-

+

{post.title}

-

+

{post.excerpt}

@@ -181,17 +181,17 @@ function BlogPostCard({ post, locale }: { post: BlogPost; locale: string }) { {post.tags?.slice(0, 3).map((tag, index) => ( {tag} ))} {post.tags && post.tags.length > 3 && ( - + +{post.tags.length - 3} more )} @@ -199,11 +199,11 @@ function BlogPostCard({ post, locale }: { post: BlogPost; locale: string }) { {/* Link Icon */}
- +
@@ -266,9 +266,9 @@ function Pagination({ {currentPage > 1 ? ( 2 ? `?page=${currentPage - 1}` : ''}`} - className="flex items-center gap-1 px-3 py-2 text-sm text-zinc-400 hover:text-white - bg-zinc-800/50 hover:bg-zinc-800 rounded-lg ring-1 ring-zinc-700/50 - hover:ring-zinc-600 transition-all duration-200" + className="flex items-center gap-1 px-3 py-2 text-sm text-muted-foreground hover:text-foreground + bg-card/50 hover:bg-card rounded-lg ring-1 ring-border/50 + hover:ring-accent transition-all duration-200" aria-label={t('ui.pagination.previous')} > @@ -276,8 +276,8 @@ function Pagination({ ) : ( @@ -290,7 +290,7 @@ function Pagination({ {getPageNumbers().map((page, index) => { if (page === 'ellipsis') { return ( - + ... ); @@ -306,7 +306,7 @@ function Pagination({ ring-1 transition-all duration-200 ${isCurrentPage ? 'bg-[#697565] text-white ring-[#697565] font-medium' - : 'text-zinc-400 hover:text-white bg-zinc-800/50 hover:bg-zinc-800 ring-zinc-700/50 hover:ring-zinc-600' + : 'text-muted-foreground hover:text-foreground bg-card/50 hover:bg-card ring-border/50 hover:ring-accent' }`} aria-current={isCurrentPage ? 'page' : undefined} > @@ -320,9 +320,9 @@ function Pagination({ {currentPage < totalPages ? ( {t('ui.pagination.next')} @@ -330,8 +330,8 @@ function Pagination({ ) : ( {t('ui.pagination.next')} @@ -387,17 +387,17 @@ export default async function BlogPage({ params, searchParams }: Props) { {/* Header Section */}
- -

BLOG

+ +

BLOG

-

+

{t('meta.header.title')}

-

+

{t('meta.header.subtitle')}

{/* Post count */} -

+

{t('ui.pagination.showing', { start: startIndex + 1, end: Math.min(endIndex, allPosts.length), @@ -424,7 +424,7 @@ export default async function BlogPage({ params, searchParams }: Props) { {/* Empty State */} {posts.length === 0 && (

-

{t('ui.errors.posts')}

+

{t('ui.errors.posts')}

)}
diff --git a/src/app/[locale]/imprint/page.tsx b/src/app/[locale]/imprint/page.tsx index 9b17756..88b97db 100644 --- a/src/app/[locale]/imprint/page.tsx +++ b/src/app/[locale]/imprint/page.tsx @@ -221,21 +221,21 @@ export default async function ImprintPage({ params }: Props) { -

{c.title}

+

{c.title}

{/* Contact */} -
-

{c.contact.title}

-
+
+

{c.contact.title}

+
{c.contact.content.map((line, index) => (

{line}

))} @@ -244,25 +244,25 @@ export default async function ImprintPage({ params }: Props) { {/* Liability */}
-

{c.liability.title}

+

{c.liability.title}

{c.liability.sections.map((section, index) => (
-

{section.title}

-

{section.content}

+

{section.title}

+

{section.content}

))}
{/* Copyright */}
-

{c.copyright.title}

-

{c.copyright.content}

+

{c.copyright.title}

+

{c.copyright.content}

{/* Images */}
-

{c.images.title}

-