first commit

This commit is contained in:
Adrian Miesikowski 2026-02-10 13:34:42 +01:00
commit a10d92abac
57 changed files with 4952 additions and 0 deletions

12
.dockerignore Normal file
View File

@ -0,0 +1,12 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
.gitignore
*.md
.env*.local
.DS_Store
*.pem

41
.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

47
Dockerfile Normal file
View File

@ -0,0 +1,47 @@
# Multi-stage build for Next.js application
FROM node:20-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
RUN npm ci
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Set environment variables for build
ENV NEXT_TELEMETRY_DISABLED=1
# Build the application
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy built application
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

17
Dockerfile.dev Normal file
View File

@ -0,0 +1,17 @@
# Development Dockerfile for Next.js with hot reload
FROM node:20-alpine
WORKDIR /app
# Install dependencies
COPY package.json package-lock.json* ./
RUN npm ci
# Copy application code
COPY . .
# Expose development port
EXPOSE 3000
# Start development server
CMD ["npm", "run", "dev"]

36
README.md Normal file
View File

@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

55
app/about/page.tsx Normal file
View File

@ -0,0 +1,55 @@
import type { Metadata } from "next";
import AboutHero from "@/components/AboutHero";
import Mission from "@/components/Mission";
import Values from "@/components/Values";
import Team from "@/components/Team";
import CTA from "@/components/CTA";
export const metadata: Metadata = {
title: "O nas — Specjaliści Sztucznej Inteligencji | SZMYT AI Labs",
description:
"Zespół ekspertów AI ✓ Doświadczenie w projektach dla różnych branż ✓ Transparentność i efektywność ✓ Kompleksowe wdrożenia AI. Poznaj naszą misję!",
keywords: [
"zespół AI",
"eksperci sztucznej inteligencji",
"specjaliści AI Polska",
"doświadczenie AI",
"firma AI",
"konsultanci sztucznej inteligencji",
],
openGraph: {
title: "O nas — Specjaliści Sztucznej Inteligencji | SZMYT AI Labs",
description:
"Zespół ekspertów AI ✓ Doświadczenie w projektach dla różnych branż ✓ Transparentność i efektywność ✓ Kompleksowe wdrożenia AI.",
url: "https://sztucznainteligencjadlafirm.pl/about/",
},
alternates: { canonical: "https://sztucznainteligencjadlafirm.pl/about/" },
};
const pageSchema = {
"@context": "https://schema.org",
"@type": "WebPage",
name: "O nas — Specjaliści Sztucznej Inteligencji",
url: "https://sztucznainteligencjadlafirm.pl/about/",
description: "Zespół ekspertów AI z doświadczeniem w projektach dla różnych branż. Transparentność, efektywność i kompleksowe wdrożenia AI.",
breadcrumb: {
"@type": "BreadcrumbList",
itemListElement: [
{ "@type": "ListItem", position: 1, name: "Strona główna", item: "https://sztucznainteligencjadlafirm.pl/" },
{ "@type": "ListItem", position: 2, name: "O nas", item: "https://sztucznainteligencjadlafirm.pl/about/" },
],
},
};
export default function About() {
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(pageSchema) }} />
<AboutHero />
<Mission />
<Values />
<Team />
<CTA />
</>
);
}

View File

@ -0,0 +1,23 @@
import { NextResponse } from "next/server";
import { getPostBySlug } from "@/lib/blog";
export const dynamic = "force-dynamic";
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
try {
const { slug } = await params;
const post = await getPostBySlug(slug);
if (!post) {
return NextResponse.json({ success: false, error: "Post not found" }, { status: 404 });
}
return NextResponse.json({
success: true,
post,
});
} catch (error) {
console.error("API Error:", error);
return NextResponse.json({ success: false, error: "Failed to fetch post" }, { status: 500 });
}
}

22
app/api/blog/route.ts Normal file
View File

@ -0,0 +1,22 @@
import { NextResponse } from "next/server";
import { getAllPosts } from "@/lib/blog";
export const dynamic = "force-dynamic";
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const category = searchParams.get("category") as "case-study" | "blog" | null;
const posts = await getAllPosts(category || undefined);
return NextResponse.json({
success: true,
posts,
count: posts.length,
});
} catch (error) {
console.error("API Error:", error);
return NextResponse.json({ success: false, error: "Failed to fetch posts" }, { status: 500 });
}
}

34
app/api/contact/route.ts Normal file
View File

@ -0,0 +1,34 @@
import { NextResponse } from "next/server";
import { readFileSync, writeFileSync } from "fs";
import { resolve } from "path";
const SUBMISSIONS_PATH = resolve(process.cwd(), "data/submissions.json");
export async function POST(request: Request) {
try {
const { name, email, message } = await request.json();
if (!name || !email || !message) {
return NextResponse.json({ error: "All fields are required" }, { status: 400 });
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return NextResponse.json({ error: "Invalid email" }, { status: 400 });
}
const submissions = JSON.parse(readFileSync(SUBMISSIONS_PATH, "utf-8"));
submissions.push({
name,
email,
message,
createdAt: new Date().toISOString(),
});
writeFileSync(SUBMISSIONS_PATH, JSON.stringify(submissions, null, 2), "utf-8");
return NextResponse.json({ success: true }, { status: 200 });
} catch (err) {
console.error("Contact form error:", err);
return NextResponse.json({ error: "Server error" }, { status: 500 });
}
}

8
app/api/health/route.ts Normal file
View File

@ -0,0 +1,8 @@
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({
status: "ok",
timestamp: new Date().toISOString(),
});
}

92
app/blog/[slug]/page.tsx Normal file
View File

@ -0,0 +1,92 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { getAllPosts, getPostBySlug } from "@/lib/blog";
import BlogPost from "@/components/BlogPost";
// ISR: Revalidate every 60 seconds
export const revalidate = 60;
// Generate static params for all blog posts
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map((post) => ({
slug: post.slug,
}));
}
// Generate metadata for each post
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
const { slug } = await params;
const post = await getPostBySlug(slug);
if (!post) {
return {
title: "Post nie znaleziony — SZMYT AI Labs",
};
}
return {
title: post.seo?.title || `${post.title} — SZMYT AI Labs`,
description: post.seo?.description || post.excerpt,
keywords: post.seo?.keywords || post.tags,
openGraph: {
title: post.seo?.title || post.title,
description: post.seo?.description || post.excerpt,
url: `https://sztucznainteligencjadlafirm.pl/blog/${post.slug}/`,
type: "article",
publishedTime: post.publishedAt.toISOString(),
modifiedTime: post.updatedAt.toISOString(),
authors: [post.author],
images: post.coverImage ? [{ url: post.coverImage }] : [],
},
alternates: { canonical: `https://sztucznainteligencjadlafirm.pl/blog/${post.slug}/` },
};
}
export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPostBySlug(slug);
if (!post) {
notFound();
}
const articleSchema = {
"@context": "https://schema.org",
"@type": post.category === "case-study" ? "Case Study" : "BlogPosting",
headline: post.title,
description: post.excerpt,
image: post.coverImage,
datePublished: post.publishedAt.toISOString(),
dateModified: post.updatedAt.toISOString(),
author: {
"@type": "Person",
name: post.author,
},
publisher: {
"@type": "Organization",
name: "SZMYT AI Labs",
url: "https://sztucznainteligencjadlafirm.pl",
},
mainEntityOfPage: {
"@type": "WebPage",
"@id": `https://sztucznainteligencjadlafirm.pl/blog/${post.slug}/`,
},
keywords: post.tags.join(", "),
breadcrumb: {
"@type": "BreadcrumbList",
itemListElement: [
{ "@type": "ListItem", position: 1, name: "Strona główna", item: "https://sztucznainteligencjadlafirm.pl/" },
{ "@type": "ListItem", position: 2, name: "Blog", item: "https://sztucznainteligencjadlafirm.pl/blog/" },
{ "@type": "ListItem", position: 3, name: post.title, item: `https://sztucznainteligencjadlafirm.pl/blog/${post.slug}/` },
],
},
};
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(articleSchema) }} />
<BlogPost post={post} />
</>
);
}

74
app/blog/page.tsx Normal file
View File

@ -0,0 +1,74 @@
import type { Metadata } from "next";
import { getAllPosts } from "@/lib/blog";
import BlogList from "@/components/BlogList";
// Revalidate every 60 seconds
export const revalidate = 60;
export const metadata: Metadata = {
title: "Blog AI i Case Studies — SZMYT AI Labs",
description:
"✓ Case studies wdrożeń AI ✓ Blog o sztucznej inteligencji dla firm ✓ Praktyczne porady i przykłady ✓ Najnowsze trendy w AI dla biznesu",
keywords: [
"blog AI",
"case studies AI",
"wdrożenia AI przykłady",
"sztuczna inteligencja blog",
"AI dla firm blog",
"przykłady automatyzacji AI",
],
openGraph: {
title: "Blog AI i Case Studies — SZMYT AI Labs",
description:
"✓ Case studies wdrożeń AI ✓ Blog o sztucznej inteligencji dla firm ✓ Praktyczne porady i przykłady",
url: "https://sztucznainteligencjadlafirm.pl/blog/",
},
alternates: { canonical: "https://sztucznainteligencjadlafirm.pl/blog/" },
};
const pageSchema = {
"@context": "https://schema.org",
"@type": "Blog",
name: "Blog SZMYT AI Labs",
url: "https://sztucznainteligencjadlafirm.pl/blog/",
description: "Blog o sztucznej inteligencji dla firm, case studies wdrożeń AI i praktyczne porady",
publisher: {
"@type": "Organization",
name: "SZMYT AI Labs",
url: "https://sztucznainteligencjadlafirm.pl",
},
breadcrumb: {
"@type": "BreadcrumbList",
itemListElement: [
{ "@type": "ListItem", position: 1, name: "Strona główna", item: "https://sztucznainteligencjadlafirm.pl/" },
{ "@type": "ListItem", position: 2, name: "Blog", item: "https://sztucznainteligencjadlafirm.pl/blog/" },
],
},
};
export default async function BlogPage() {
const posts = await getAllPosts();
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(pageSchema) }} />
<section className="relative min-h-screen py-20 px-4 pt-24 bg-gray-950">
<div className="absolute inset-0 overflow-hidden">
<div className="absolute top-1/4 left-1/2 -translate-x-1/2 w-[600px] h-[600px] bg-cyan-500/5 rounded-full blur-3xl" />
</div>
<div className="relative z-10 max-w-6xl mx-auto">
<div className="text-center mb-14">
<p className="text-cyan-400 font-medium tracking-widest uppercase text-sm mb-4">Blog & Case Studies</p>
<h1 className="text-4xl md:text-6xl font-bold text-white mb-6">
Wiedza z pierwszej ręki o <span className="text-cyan-400">AI dla firm</span>
</h1>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
Przykłady wdrożeń, praktyczne porady i najnowsze trendy w automatyzacji biznesu z AI
</p>
</div>
<BlogList posts={posts} />
</div>
</section>
</>
);
}

BIN
app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

69
app/globals.css Normal file
View File

@ -0,0 +1,69 @@
@import "tailwindcss";
:root {
--background: #030712;
--foreground: #f9fafb;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
/* Glow utilities */
.glow-cyan {
box-shadow: 0 0 20px rgba(6, 182, 212, 0.3);
}
.glow-cyan-hover:hover {
box-shadow: 0 0 28px rgba(6, 182, 212, 0.5);
}
.border-glow-left {
border-left: 3px solid rgba(6, 182, 212, 0.8);
box-shadow: -4px 0 15px rgba(6, 182, 212, 0.2);
}
.text-glow {
text-shadow: 0 0 24px rgba(6, 182, 212, 0.6);
}
/* Carousel scroll animations */
@keyframes carousel-left {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
@keyframes carousel-right {
0% { transform: translateX(-50%); }
100% { transform: translateX(0); }
}
/* Animated gradient background */
@keyframes gradient-shift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.animate-gradient-bg {
background-size: 200% 200%;
animation: gradient-shift 8s ease infinite;
}
/* Icon glow pulse */
@keyframes icon-glow-pulse {
0%, 100% { filter: drop-shadow(0 0 3px rgba(6, 182, 212, 0.3)); }
50% { filter: drop-shadow(0 0 12px rgba(6, 182, 212, 0.7)); }
}
.icon-pulse {
animation: icon-glow-pulse 3s ease-in-out infinite;
}

81
app/layout.tsx Normal file
View File

@ -0,0 +1,81 @@
import type { Metadata } from "next";
import { Geist } from "next/font/google";
import "./globals.css";
import Nav from "@/components/Nav";
import Footer from "@/components/Footer";
import GoogleAnalytics from "@/components/GoogleAnalytics";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "SZMYT AI Labs — Sztuczna Inteligencja dla Firm | AI Agenty",
description:
"✓ Sztuczna inteligencja dla firm ✓ Automatyzacja procesów z AI ✓ Dedykowane agenty AI ✓ Integracja z systemami firmowymi ✓ Wdrożenie w 40h. Zwiększ efektywność!",
keywords: [
"sztuczna inteligencja dla firm",
"AI dla biznesu",
"agenty AI",
"automatyzacja AI",
"wdrożenie AI",
"ChatGPT dla firm",
"Claude AI",
"AI w procesach biznesowych",
"inteligentna automatyzacja",
"AI chatbot firmowy",
"machine learning dla firm",
"AI konsultacje",
],
robots: { index: true, follow: true },
icons: { icon: "/favicon.svg" },
openGraph: {
type: "website",
locale: "pl_PL",
siteName: "SZMYT AI Labs",
url: "https://sztucznainteligencjadlafirm.pl",
title: "SZMYT AI Labs — Sztuczna Inteligencja dla Firm | AI Agenty",
description:
"✓ Sztuczna inteligencja dla firm ✓ Automatyzacja procesów z AI ✓ Dedykowane agenty AI ✓ Integracja z systemami firmowymi ✓ Wdrożenie w 40h.",
images: [{ url: "https://sztucznainteligencjadlafirm.pl/og-image.png", width: 1200, height: 630 }],
},
twitter: { card: "summary_large_image", images: ["https://sztucznainteligencjadlafirm.pl/og-image.png"] },
alternates: { canonical: "https://sztucznainteligencjadlafirm.pl" },
};
const jsonLd = {
"@context": "https://schema.org",
"@type": "Organization",
name: "SZMYT AI Labs",
url: "https://sztucznainteligencjadlafirm.pl",
description:
"Budujemy dedykowane agenty AI dla firm. Automatyzacja biznesu z siłą sztucznej inteligencji.",
contactPoint: {
"@type": "ContactPoint",
email: "kontakt@sztucznainteligencjadlafirm.pl",
contactType: "customer service",
},
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="pl">
<head>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
</head>
<body className={`${geistSans.variable} antialiased bg-gray-950 text-white min-h-screen`}>
{process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID && (
<GoogleAnalytics GA_MEASUREMENT_ID={process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID} />
)}
<Nav />
<main>{children}</main>
<Footer />
</body>
</html>
);
}

53
app/oferta/page.tsx Normal file
View File

@ -0,0 +1,53 @@
import type { Metadata } from "next";
import OfertaHero from "@/components/OfertaHero";
import OfertaServices from "@/components/OfertaServices";
import CTA from "@/components/CTA";
export const metadata: Metadata = {
title: "Oferta Sztucznej Inteligencji dla Firm — AI na Wyciągnięcie Ręki | SZMYT AI Labs",
description:
"Kompleksowa oferta AI ✓ Analiza i optymalizacja procesów ✓ Budowa agentów AI ✓ Integracje systemowe ✓ Monitoring 24/7 ✓ Wsparcie techniczne. Bezpłatna konsultacja!",
keywords: [
"oferta AI",
"sztuczna inteligencja oferta",
"wdrożenie AI cena",
"usługi AI dla firm",
"konsultacje AI",
"analiza procesów AI",
"integracja AI",
"cennik AI",
],
openGraph: {
title: "Oferta Sztucznej Inteligencji dla Firm — AI na Wyciągnięcie Ręki | SZMYT AI Labs",
description:
"Kompleksowa oferta AI ✓ Analiza i optymalizacja procesów ✓ Budowa agentów AI ✓ Integracje systemowe ✓ Monitoring 24/7.",
url: "https://sztucznainteligencjadlafirm.pl/oferta/",
},
alternates: { canonical: "https://sztucznainteligencjadlafirm.pl/oferta/" },
};
const pageSchema = {
"@context": "https://schema.org",
"@type": "WebPage",
name: "Oferta Sztucznej Inteligencji dla Firm",
url: "https://sztucznainteligencjadlafirm.pl/oferta/",
description: "Kompleksowa oferta AI: analiza i optymalizacja procesów, budowa agentów AI, integracje systemowe, monitoring 24/7. Bezpłatna konsultacja.",
breadcrumb: {
"@type": "BreadcrumbList",
itemListElement: [
{ "@type": "ListItem", position: 1, name: "Strona główna", item: "https://sztucznainteligencjadlafirm.pl/" },
{ "@type": "ListItem", position: 2, name: "Oferta", item: "https://sztucznainteligencjadlafirm.pl/oferta/" },
],
},
};
export default function Oferta() {
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(pageSchema) }} />
<OfertaHero />
<OfertaServices />
<CTA />
</>
);
}

166
app/page.tsx Normal file
View File

@ -0,0 +1,166 @@
import type { Metadata } from "next";
import Hero from "@/components/Hero";
import WhatWeDo from "@/components/WhatWeDo";
import HowItWorks from "@/components/HowItWorks";
import WhyUs from "@/components/WhyUs";
import ContactForm from "@/components/ContactForm";
import LogoCarousel, { AI_TOOLS, PLATFORMS } from "@/components/LogoCarousel";
import Stats from "@/components/Stats";
import ScrollReveal from "@/components/ScrollReveal";
import FeaturedBlog from "@/components/FeaturedBlog";
import { getFeaturedPosts } from "@/lib/blog";
// Revalidate every 60 seconds
export const revalidate = 60;
export const metadata: Metadata = {
title: "Sztuczna Inteligencja dla Firm — Wdrożenie AI w Biznesie | SZMYT AI Labs",
description:
"Wdróż sztuczną inteligencję w swojej firmie ✓ AI agenty ✓ Automatyzacja procesów ✓ Integracja z CRM, Slack, Teams ✓ 98% zadowolonych klientów. Bezpłatna konsultacja!",
keywords: [
"sztuczna inteligencja dla firm",
"wdrożenie AI",
"AI w biznesie",
"automatyzacja AI",
"agenty AI dla firm",
"ChatGPT dla biznesu",
"AI chatbot",
"inteligentna automatyzacja",
"machine learning firma",
],
openGraph: {
title: "Sztuczna Inteligencja dla Firm — Wdrożenie AI w Biznesie | SZMYT AI Labs",
description:
"Wdróż sztuczną inteligencję w swojej firmie ✓ AI agenty ✓ Automatyzacja procesów ✓ Integracja z CRM, Slack, Teams ✓ 98% zadowolonych.",
url: "https://sztucznainteligencjadlafirm.pl/",
},
alternates: { canonical: "https://sztucznainteligencjadlafirm.pl/" },
};
const pageSchema = [
{
"@context": "https://schema.org",
"@type": "WebSite",
name: "SZMYT AI Labs",
url: "https://sztucznainteligencjadlafirm.pl",
potentialAction: {
"@type": "SearchAction",
target: "https://sztucznainteligencjadlafirm.pl/?q={search_term_string}",
"query-input": "required name=search_term_string",
},
},
{
"@context": "https://schema.org",
"@type": "WebPage",
name: "Sztuczna Inteligencja dla Firm — Wdrożenie AI w Biznesie",
url: "https://sztucznainteligencjadlafirm.pl/",
description: "Wdróż sztuczną inteligencję w swojej firmie. AI agenty, automatyzacja procesów, integracja z systemami. 98% zadowolonych klientów.",
breadcrumb: {
"@type": "BreadcrumbList",
itemListElement: [{ "@type": "ListItem", position: 1, name: "Strona główna", item: "https://sztucznainteligencjadlafirm.pl/" }],
},
},
{
"@context": "https://schema.org",
"@type": "Service",
name: "Analiza procesów biznesowych AI",
provider: { "@type": "Organization", name: "SZMYT AI Labs", url: "https://sztucznainteligencjadlafirm.pl" },
description: "Mapujemy procesy biznesowe i identyfikujemy obszary idealne do automatyzacji z wykorzystaniem sztucznej inteligencji.",
serviceType: "Konsultacje AI",
areaServed: "PL",
},
{
"@context": "https://schema.org",
"@type": "Service",
name: "Wdrożenie sztucznej inteligencji",
provider: { "@type": "Organization", name: "SZMYT AI Labs", url: "https://sztucznainteligencjadlafirm.pl" },
description: "Tworzymy i wdrażamy agenty AI dopasowane do potrzeb firmy. Pełna integracja z istniejącymi systemami.",
serviceType: "Wdrożenie AI",
areaServed: "PL",
},
{
"@context": "https://schema.org",
"@type": "Service",
name: "Monitoring i optymalizacja systemów AI",
provider: { "@type": "Organization", name: "SZMYT AI Labs", url: "https://sztucznainteligencjadlafirm.pl" },
description: "Śledzimy i optymalizujemy wydajność systemów AI w czasie rzeczywistym. Wsparcie techniczne 24/7.",
serviceType: "Monitoring AI",
areaServed: "PL",
},
{
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: [
{
"@type": "Question",
name: "Jak sztuczna inteligencja może pomóc mojej firmie?",
acceptedAnswer: {
"@type": "Answer",
text: "Sztuczna inteligencja automatyzuje rutynowe zadania, analizuje dane w czasie rzeczywistym, obsługuje klientów 24/7 i zwiększa efektywność procesów biznesowych nawet 3-krotnie. AI może być wdrożone w obsłudze klienta, analizie danych, automatyzacji procesów czy personalizacji oferty.",
},
},
{
"@type": "Question",
name: "Ile czasu zajmuje wdrożenie AI w firmie?",
acceptedAnswer: {
"@type": "Answer",
text: "Typowe wdrożenie zajmuje około 40 godzin roboczych i obejmuje analizę procesów, konfigurację systemu AI, testy oraz integrację z istniejącymi narzędziami. Złożone projekty mogą wymagać więcej czasu.",
},
},
{
"@type": "Question",
name: "Z jakimi narzędziami integruje się sztuczna inteligencja?",
acceptedAnswer: {
"@type": "Answer",
text: "Systemy AI można zintegrować z Slack, Microsoft Teams, systemami CRM (Salesforce, HubSpot), platformami e-commerce, narzędziami projektowymi (Jira, Asana), bazami danych oraz własnym API firmy.",
},
},
{
"@type": "Question",
name: "Czy wdrożenie AI jest bezpieczne dla danych firmy?",
acceptedAnswer: {
"@type": "Answer",
text: "Tak, bezpieczeństwo danych jest priorytetem. Wszystkie wdrożenia AI są zgodne z RODO, dane są szyfrowane, a systemy projektowane z uwzględnieniem najlepszych praktyk cyberbezpieczeństwa. Możliwe jest również wdrożenie rozwiązań on-premise.",
},
},
{
"@type": "Question",
name: "Ile kosztuje wdrożenie sztucznej inteligencji?",
acceptedAnswer: {
"@type": "Answer",
text: "Koszt wdrożenia AI zależy od zakresu projektu, liczby integracji i złożoności procesów. Oferujemy bezpłatną konsultację, podczas której oszacujemy potrzeby i przedstawimy ofertę dopasowaną do budżetu firmy.",
},
},
],
},
];
export default async function Home() {
const featuredPosts = await getFeaturedPosts(3);
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(pageSchema) }} />
<Hero />
<WhatWeDo />
<Stats />
<LogoCarousel
title="Narzędzia, które znamy"
subtitle="Technologie AI, z którymi pracujemy na co dzień"
logos={AI_TOOLS}
/>
<HowItWorks />
<LogoCarousel
title="Platformy, z którymi się integrujemy"
subtitle="Podłączamy AI do narzędzi, które już masz"
logos={PLATFORMS}
reverse
/>
<WhyUs />
<FeaturedBlog posts={featuredPosts} />
<ScrollReveal>
<ContactForm />
</ScrollReveal>
</>
);
}

51
app/sitemap.ts Normal file
View File

@ -0,0 +1,51 @@
import { MetadataRoute } from "next";
import { getAllPosts } from "@/lib/blog";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = "https://sztucznainteligencjadlafirm.pl";
// Static pages
const routes = [
{
url: `${baseUrl}/`,
lastModified: new Date(),
changeFrequency: "monthly" as const,
priority: 1.0,
},
{
url: `${baseUrl}/about/`,
lastModified: new Date(),
changeFrequency: "monthly" as const,
priority: 0.8,
},
{
url: `${baseUrl}/oferta/`,
lastModified: new Date(),
changeFrequency: "monthly" as const,
priority: 0.9,
},
{
url: `${baseUrl}/blog/`,
lastModified: new Date(),
changeFrequency: "weekly" as const,
priority: 0.9,
},
];
// Dynamic blog posts
try {
const posts = await getAllPosts();
const blogPosts = posts.map((post) => ({
url: `${baseUrl}/blog/${post.slug}/`,
lastModified: new Date(post.updatedAt),
changeFrequency: "weekly" as const,
priority: 0.7,
}));
return [...routes, ...blogPosts];
} catch (error) {
console.error("Error generating sitemap:", error);
// Return static routes if blog posts fail to load
return routes;
}
}

14
components/AboutHero.tsx Normal file
View File

@ -0,0 +1,14 @@
export default function AboutHero() {
return (
<section className="relative py-32 px-4 pt-28 bg-gray-950">
<div className="absolute inset-0 overflow-hidden">
<div className="absolute top-0 right-1/4 w-[500px] h-[500px] bg-cyan-500/5 rounded-full blur-3xl" />
</div>
<div className="relative z-10 max-w-4xl mx-auto text-center">
<p className="text-cyan-400 font-medium tracking-widest uppercase text-sm mb-4">SZMYT AI Labs</p>
<h1 className="text-5xl md:text-6xl font-bold text-white mb-4">O nas</h1>
<p className="text-gray-400 text-xl max-w-2xl mx-auto">Poznaj zespół za SZMYT AI Labs</p>
</div>
</section>
);
}

52
components/BlogCard.tsx Normal file
View File

@ -0,0 +1,52 @@
import Link from "next/link";
import Image from "next/image";
import type { BlogPost } from "@/lib/blog";
export default function BlogCard({ post }: { post: BlogPost }) {
const formattedDate = new Date(post.publishedAt).toLocaleDateString("pl-PL", {
year: "numeric",
month: "long",
day: "numeric",
});
const categoryLabel = post.category === "case-study" ? "Case Study" : "Blog";
const categoryColor = post.category === "case-study" ? "bg-purple-500/10 text-purple-400" : "bg-cyan-500/10 text-cyan-400";
return (
<Link href={`/blog/${post.slug}/`}>
<article className="bg-gray-800 border border-gray-700 rounded-2xl p-6 hover:border-cyan-500/50 hover:-translate-y-1 hover:shadow-lg hover:shadow-cyan-500/10 transition-all duration-300 h-full flex flex-col group">
<div className="mb-4 rounded-xl overflow-hidden bg-gray-700 relative h-48">
<Image
src={post.coverImage || '/blog/ai-automation.jpg'}
alt={post.title}
fill
className="object-cover group-hover:scale-105 transition-transform duration-300"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
<div className="flex items-center gap-3 mb-3">
<span className={`px-3 py-1 rounded-full text-xs font-medium ${categoryColor}`}>{categoryLabel}</span>
<time className="text-gray-500 text-sm" dateTime={post.publishedAt.toISOString()}>
{formattedDate}
</time>
</div>
<h3 className="text-xl font-semibold text-white mb-3 group-hover:text-cyan-400 transition-colors">
{post.title}
</h3>
<p className="text-gray-400 leading-relaxed mb-4 flex-grow">{post.excerpt}</p>
<div className="flex items-center justify-between pt-4 border-t border-gray-700">
<div className="flex flex-wrap gap-2">
{post.tags.slice(0, 3).map((tag) => (
<span key={tag} className="text-xs text-gray-500">
#{tag}
</span>
))}
</div>
<span className="text-cyan-400 text-sm font-medium group-hover:translate-x-1 transition-transform">
Czytaj więcej
</span>
</div>
</article>
</Link>
);
}

65
components/BlogList.tsx Normal file
View File

@ -0,0 +1,65 @@
"use client";
import { useState } from "react";
import type { BlogPost } from "@/lib/blog";
import BlogCard from "./BlogCard";
import ScrollReveal from "./ScrollReveal";
export default function BlogList({ posts }: { posts: BlogPost[] }) {
const [filter, setFilter] = useState<"all" | "blog" | "case-study">("all");
const filteredPosts = filter === "all" ? posts : posts.filter((p) => p.category === filter);
return (
<div>
{/* Filter Tabs */}
<div className="flex justify-center gap-4 mb-12">
<button
onClick={() => setFilter("all")}
className={`px-6 py-3 rounded-full font-medium transition-all ${
filter === "all"
? "bg-cyan-600 text-white shadow-lg shadow-cyan-500/30"
: "bg-gray-800 text-gray-400 hover:bg-gray-700"
}`}
>
Wszystkie ({posts.length})
</button>
<button
onClick={() => setFilter("blog")}
className={`px-6 py-3 rounded-full font-medium transition-all ${
filter === "blog"
? "bg-cyan-600 text-white shadow-lg shadow-cyan-500/30"
: "bg-gray-800 text-gray-400 hover:bg-gray-700"
}`}
>
Blog ({posts.filter((p) => p.category === "blog").length})
</button>
<button
onClick={() => setFilter("case-study")}
className={`px-6 py-3 rounded-full font-medium transition-all ${
filter === "case-study"
? "bg-cyan-600 text-white shadow-lg shadow-cyan-500/30"
: "bg-gray-800 text-gray-400 hover:bg-gray-700"
}`}
>
Case Studies ({posts.filter((p) => p.category === "case-study").length})
</button>
</div>
{/* Posts Grid */}
{filteredPosts.length === 0 ? (
<div className="text-center py-20">
<p className="text-gray-500 text-lg">Brak postów w tej kategorii</p>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredPosts.map((post, i) => (
<ScrollReveal key={post.slug} delay={i * 100}>
<BlogCard post={post} />
</ScrollReveal>
))}
</div>
)}
</div>
);
}

199
components/BlogPost.tsx Normal file
View File

@ -0,0 +1,199 @@
"use client";
import Link from "next/link";
import type { BlogPost as BlogPostType } from "@/lib/blog";
export default function BlogPost({ post }: { post: BlogPostType }) {
const formattedDate = new Date(post.publishedAt).toLocaleDateString("pl-PL", {
year: "numeric",
month: "long",
day: "numeric",
});
const categoryLabel = post.category === "case-study" ? "Case Study" : "Blog";
const categoryColor = post.category === "case-study" ? "bg-purple-500/10 text-purple-400" : "bg-cyan-500/10 text-cyan-400";
return (
<article className="relative min-h-screen py-20 px-4 pt-24 bg-gray-950">
<div className="absolute inset-0 overflow-hidden">
<div className="absolute top-1/4 left-1/2 -translate-x-1/2 w-[600px] h-[600px] bg-cyan-500/5 rounded-full blur-3xl" />
</div>
<div className="relative z-10 max-w-4xl mx-auto">
{/* Back Link */}
<Link
href="/blog/"
className="inline-flex items-center gap-2 text-cyan-400 hover:text-cyan-300 mb-8 transition-colors"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Wróć do bloga
</Link>
{/* Category & Date */}
<div className="flex items-center gap-4 mb-6">
<span className={`px-4 py-2 rounded-full text-sm font-medium ${categoryColor}`}>{categoryLabel}</span>
<time className="text-gray-500" dateTime={post.publishedAt.toISOString()}>
{formattedDate}
</time>
</div>
{/* Title */}
<h1 className="text-4xl md:text-6xl font-bold text-white mb-6 leading-tight">{post.title}</h1>
{/* Author & Tags */}
<div className="flex flex-wrap items-center gap-4 mb-8 pb-8 border-b border-gray-800">
<p className="text-gray-400">
Autor: <span className="text-white font-medium">{post.author}</span>
</p>
<div className="flex flex-wrap gap-2">
{post.tags.map((tag) => (
<span key={tag} className="text-sm text-gray-500">
#{tag}
</span>
))}
</div>
</div>
{/* Cover Image */}
{post.coverImage && (
<div className="mb-10 rounded-2xl overflow-hidden">
<img src={post.coverImage} alt={post.title} className="w-full h-auto object-cover" />
</div>
)}
{/* Excerpt */}
<div className="bg-cyan-500/5 border-l-4 border-cyan-500 p-6 mb-10 rounded-r-xl">
<p className="text-gray-300 text-lg leading-relaxed">{post.excerpt}</p>
</div>
{/* Content */}
<div
className="blog-content"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
<style jsx>{`
.blog-content {
color: #d1d5db;
line-height: 1.8;
}
.blog-content :global(h2) {
color: #22d3ee;
font-size: 2rem;
font-weight: 700;
margin-top: 3rem;
margin-bottom: 1.5rem;
}
.blog-content :global(h3) {
color: white;
font-size: 1.5rem;
font-weight: 600;
margin-top: 2rem;
margin-bottom: 1rem;
}
.blog-content :global(p) {
color: #d1d5db;
margin-bottom: 1.5rem;
line-height: 1.8;
}
.blog-content :global(strong) {
color: white;
font-weight: 600;
}
.blog-content :global(ul) {
margin: 1.5rem 0;
padding-left: 0;
list-style: none;
}
.blog-content :global(ul li) {
color: #d1d5db;
margin-bottom: 0.75rem;
padding-left: 2rem;
position: relative;
}
.blog-content :global(ul li::before) {
content: '';
position: absolute;
left: 0.5rem;
top: 0.7rem;
width: 0.5rem;
height: 0.5rem;
background: #22d3ee;
border-radius: 50%;
}
.blog-content :global(ol) {
margin: 1.5rem 0;
padding-left: 0;
list-style: none;
counter-reset: item;
}
.blog-content :global(ol li) {
color: #d1d5db;
margin-bottom: 0.75rem;
padding-left: 2rem;
position: relative;
counter-increment: item;
}
.blog-content :global(ol li::before) {
content: counter(item) '.';
position: absolute;
left: 0;
color: #22d3ee;
font-weight: 700;
}
.blog-content :global(a) {
color: #22d3ee;
text-decoration: none;
}
.blog-content :global(a:hover) {
text-decoration: underline;
}
.blog-content :global(code) {
color: #22d3ee;
background: #111827;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.9em;
}
.blog-content :global(pre) {
background: #111827;
border: 1px solid #374151;
border-radius: 0.75rem;
padding: 1.5rem;
overflow-x: auto;
margin: 1.5rem 0;
}
`}</style>
{/* CTA */}
<div className="mt-16 p-8 bg-gray-800 border border-gray-700 rounded-2xl text-center">
<h3 className="text-2xl font-bold text-white mb-4">Zainteresowany wdrożeniem AI w swojej firmie?</h3>
<p className="text-gray-400 mb-6">
Skontaktuj się z nami i poznaj możliwości automatyzacji biznesu z AI
</p>
<Link
href="/#kontakt"
className="inline-block bg-cyan-600 hover:bg-cyan-500 text-white font-semibold px-8 py-4 rounded-full transition-all"
>
Bezpłatna Konsultacja
</Link>
</div>
</div>
</article>
);
}

24
components/CTA.tsx Normal file
View File

@ -0,0 +1,24 @@
import Link from "next/link";
export default function CTA() {
return (
<section className="py-20 px-4 bg-gray-900">
<div className="max-w-4xl mx-auto">
<div className="bg-gray-800 border border-gray-700 rounded-2xl p-12 text-center relative overflow-hidden">
<div className="absolute inset-0 overflow-hidden">
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[600px] h-[300px] bg-cyan-500/5 rounded-full blur-2xl" />
</div>
<div className="relative z-10">
<h2 className="text-4xl font-bold text-white mb-4">Gotowi do współpracy?</h2>
<p className="text-gray-300 text-lg mb-8 max-w-xl mx-auto">
Skontaktuj się z nami i zobaczmy, jak AI może pomóc Twojej firmie.
</p>
<Link href="/#kontakt" className="inline-block bg-cyan-600 hover:bg-cyan-500 text-white font-semibold px-8 py-4 rounded-full glow-cyan glow-cyan-hover transition-all text-lg">
Porozmawiajmy
</Link>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,23 @@
export default function ContactForm() {
return (
<section id="kontakt" className="py-20 px-4 bg-gray-900">
<div className="max-w-2xl mx-auto">
<div className="text-center mb-10">
<h2 className="text-4xl font-bold text-white mb-4">Skontaktuj się z nami</h2>
<p className="text-gray-300 text-lg">Masz pytania? Chętnie porozmawiam.</p>
</div>
<div className="bg-gray-800 border border-gray-700 rounded-2xl p-10 text-center">
<p className="text-gray-200 text-lg mb-8 max-w-lg mx-auto leading-relaxed">
Napisz do nas e-mail i opowiedz o Twoim biznesie. Odpowiemy jak najszybciej.
</p>
<a
href="mailto:kontakt@sztucznainteligencjadlafirm.pl"
className="inline-block bg-cyan-600 hover:bg-cyan-500 text-white font-semibold px-8 py-4 rounded-full glow-cyan glow-cyan-hover transition-all text-lg"
>
Napisz do nas
</a>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,97 @@
"use client";
import Link from "next/link";
import Image from "next/image";
import { BlogPost } from "@/lib/blog";
interface FeaturedBlogProps {
posts: BlogPost[];
}
const CalendarIcon = () => (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
<line x1="16" y1="2" x2="16" y2="6" />
<line x1="8" y1="2" x2="8" y2="6" />
<line x1="3" y1="10" x2="21" y2="10" />
</svg>
);
const ArrowRightIcon = () => (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<line x1="5" y1="12" x2="19" y2="12" />
<polyline points="12 5 19 12 12 19" />
</svg>
);
export default function FeaturedBlog({ posts }: FeaturedBlogProps) {
if (!posts || posts.length === 0) {
return null;
}
return (
<section className="py-20 bg-gray-900">
<div className="max-w-6xl mx-auto px-4">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl font-bold text-white mb-4">
Najnowsze wpisy z bloga
</h2>
<p className="text-gray-400 text-lg">
Dowiedz się więcej o AI, automatyzacji i innowacjach technologicznych
</p>
</div>
<div className="grid md:grid-cols-3 gap-8 mb-12">
{posts.slice(0, 3).map((post) => (
<Link
key={post.slug}
href={`/blog/${post.slug}`}
className="group bg-gray-800 rounded-lg overflow-hidden border border-gray-700 hover:border-cyan-500 transition-all duration-300"
>
<div className="aspect-video overflow-hidden bg-gray-700 relative">
<Image
src={post.coverImage || '/blog/ai-automation.jpg'}
alt={post.title}
fill
className="object-cover group-hover:scale-105 transition-transform duration-300"
sizes="(max-width: 768px) 100vw, 33vw"
/>
</div>
<div className="p-6">
<div className="flex items-center gap-2 text-sm text-gray-400 mb-3">
<CalendarIcon />
{new Date(post.publishedAt).toLocaleDateString("pl-PL", {
year: "numeric",
month: "long",
day: "numeric",
})}
</div>
<h3 className="text-xl font-bold text-white mb-2 group-hover:text-cyan-400 transition-colors">
{post.title}
</h3>
<p className="text-gray-400 text-sm line-clamp-2 mb-4">
{post.excerpt}
</p>
<div className="flex items-center text-cyan-400 text-sm font-medium">
Czytaj więcej
<span className="ml-2 group-hover:translate-x-1 transition-transform inline-block">
<ArrowRightIcon />
</span>
</div>
</div>
</Link>
))}
</div>
<div className="text-center">
<Link
href="/blog"
className="inline-flex items-center gap-2 px-6 py-3 bg-cyan-500 hover:bg-cyan-600 text-white font-medium rounded-lg transition-colors"
>
Zobacz wszystkie wpisy
<ArrowRightIcon />
</Link>
</div>
</div>
</section>
);
}

22
components/Footer.tsx Normal file
View File

@ -0,0 +1,22 @@
import Link from "next/link";
export default function Footer() {
return (
<footer className="bg-gray-950 border-t border-gray-800 py-12 mt-16">
<div className="max-w-6xl mx-auto px-4 flex flex-col md:flex-row items-center justify-between gap-6">
<div>
<p className="text-xl font-bold text-white text-glow">SZMYT AI Labs</p>
<p className="text-gray-500 text-sm mt-1">AI Agenty dla Twojej Firmy</p>
</div>
<div className="flex gap-8">
<Link href="/" className="text-gray-400 hover:text-cyan-400 transition-colors text-sm">Strona główna</Link>
<Link href="/oferta" className="text-gray-400 hover:text-cyan-400 transition-colors text-sm">Oferta</Link>
<Link href="/blog" className="text-gray-400 hover:text-cyan-400 transition-colors text-sm">Blog</Link>
<Link href="/about" className="text-gray-400 hover:text-cyan-400 transition-colors text-sm">O nas</Link>
<Link href="/#kontakt" className="text-gray-400 hover:text-cyan-400 transition-colors text-sm">Kontakt</Link>
</div>
<p className="text-gray-600 text-sm">© 2026 SZMYT AI Labs. Wszystkie prawa zastrzeżone.</p>
</div>
</footer>
);
}

View File

@ -0,0 +1,28 @@
"use client";
import Script from "next/script";
export default function GoogleAnalytics({ GA_MEASUREMENT_ID }: { GA_MEASUREMENT_ID: string }) {
return (
<>
<Script
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
/>
<Script
id="google-analytics"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_MEASUREMENT_ID}', {
page_path: window.location.pathname,
});
`,
}}
/>
</>
);
}

30
components/Hero.tsx Normal file
View File

@ -0,0 +1,30 @@
import Link from "next/link";
export default function Hero() {
return (
<section className="relative min-h-screen flex items-center justify-center px-4 pt-16">
<div className="absolute inset-0 overflow-hidden">
<div className="absolute inset-0 animate-gradient-bg" style={{ background: "linear-gradient(270deg, rgba(6,182,212,0.1), transparent 50%, rgba(139,92,246,0.07))" }} />
<div className="absolute top-1/4 left-1/2 -translate-x-1/2 w-[800px] h-[800px] bg-cyan-500/5 rounded-full blur-3xl" />
<div className="absolute top-1/3 left-1/4 w-[400px] h-[400px] bg-cyan-600/5 rounded-full blur-2xl" />
<div className="absolute bottom-1/4 right-1/3 w-[350px] h-[350px] bg-purple-600/4 rounded-full blur-2xl" />
</div>
<div className="relative z-10 max-w-4xl mx-auto text-center">
<p className="text-cyan-400 font-medium tracking-widest uppercase text-sm mb-6">Sztuczna Inteligencja w Twojej Firmie</p>
<h1 className="text-5xl md:text-7xl font-bold text-white mb-6 leading-tight">
Wdrażamy AI<br />
<span className="text-cyan-400 text-glow">które naprawdę działa</span>
</h1>
<p className="text-gray-300 text-xl md:text-2xl max-w-2xl mx-auto mb-10 leading-relaxed">
Kompleksowe rozwiązania sztucznej inteligencji dla firm. Od analizy procesów po pełną automatyzację. Zwiększ wydajność o 300%.
</p>
<Link
href="#kontakt"
className="inline-block bg-cyan-600 hover:bg-cyan-500 text-white font-semibold px-8 py-4 rounded-full glow-cyan glow-cyan-hover transition-all text-lg"
>
Bezpłatna Konsultacja
</Link>
</div>
</section>
);
}

50
components/HowItWorks.tsx Normal file
View File

@ -0,0 +1,50 @@
import ScrollReveal from "@/components/ScrollReveal";
export default function HowItWorks() {
const steps = [
{
number: "01",
title: "Konsultacja",
description: "Poznamy Twoje potrzeby, procesy i cele biznesowe.",
},
{
number: "02",
title: "Implementacja",
description: "Zbudujemy dedykowane agenty AI skrojone na Twoją firmę.",
},
{
number: "03",
title: "Automatyzacja",
description: "Twoja firma działa szybciej i efektywniej — automatycznie.",
},
];
return (
<section className="py-20 px-4 bg-gray-900">
<div className="max-w-6xl mx-auto">
<ScrollReveal>
<div className="text-center mb-14">
<h2 className="text-4xl font-bold text-white mb-4">Jak to działa</h2>
<p className="text-gray-400 text-lg">Trzy kroki do automatyzacji Twojego biznesu</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{steps.map((step, i) => (
<ScrollReveal key={step.title} delay={i * 200}>
<div className="relative flex flex-col items-center text-center cursor-pointer group">
{i < steps.length - 1 && (
<div className="hidden md:block absolute top-10 left-1/2 w-full h-0.5 bg-gradient-to-r from-cyan-500/50 to-transparent" />
)}
<div className="relative z-10 w-20 h-20 rounded-full bg-gray-800 border-2 border-cyan-500 shadow-lg shadow-cyan-500/20 group-hover:shadow-xl group-hover:shadow-cyan-500/40 group-hover:scale-110 flex items-center justify-center mb-6 transition-all duration-300">
<span className="text-cyan-400 font-bold text-xl">{step.number}</span>
</div>
<h3 className="text-xl font-semibold text-white group-hover:text-cyan-400 mb-2 transition-colors duration-300">{step.title}</h3>
<p className="text-gray-300 leading-relaxed max-w-xs">{step.description}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
);
}

80
components/Icons.tsx Normal file
View File

@ -0,0 +1,80 @@
export function SearchIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
);
}
export function CpuIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<rect x="4" y="4" width="16" height="16" rx="2" />
<rect x="9" y="9" width="6" height="6" />
<line x1="9" y1="1" x2="9" y2="4" />
<line x1="15" y1="1" x2="15" y2="4" />
<line x1="9" y1="20" x2="9" y2="23" />
<line x1="15" y1="20" x2="15" y2="23" />
<line x1="20" y1="9" x2="23" y2="9" />
<line x1="1" y1="9" x2="4" y2="9" />
<line x1="20" y1="15" x2="23" y2="15" />
<line x1="1" y1="15" x2="4" y2="15" />
</svg>
);
}
export function TrendingUpIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<polyline points="23 6 13.5 15.5 8.5 10.5 1 18" />
<polyline points="17 6 23 6 23 12" />
</svg>
);
}
export function LightbulbIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M12 2a7 7 0 00-7 7c0 2.38 1.19 4.47 3 5.74V17a1 1 0 001 1h6a1 1 0 001-1v-2.26C17.81 13.47 19 11.38 19 9a7 7 0 00-7-7z" />
<line x1="10" y1="22" x2="14" y2="22" />
</svg>
);
}
export function ShieldCheckIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
<polyline points="9 12 11 14 15 10" />
</svg>
);
}
export function ZapIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
</svg>
);
}
export function UsersIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M23 21v-2a4 4 0 00-3-3.87" />
<path d="M16 3.13a4 4 0 010 7.75" />
</svg>
);
}
export function UserIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" />
<circle cx="12" cy="8" r="4" />
</svg>
);
}

View File

@ -0,0 +1,74 @@
"use client";
interface LogoItem {
name: string;
color: string;
}
export const AI_TOOLS: LogoItem[] = [
{ name: "ChatGPT", color: "bg-green-400" },
{ name: "Claude", color: "bg-purple-400" },
{ name: "Gemini", color: "bg-blue-400" },
{ name: "n8n", color: "bg-orange-400" },
{ name: "Make", color: "bg-violet-400" },
{ name: "Zapier", color: "bg-yellow-400" },
{ name: "LangChain", color: "bg-emerald-400" },
{ name: "OpenAI", color: "bg-cyan-400" },
];
export const PLATFORMS: LogoItem[] = [
{ name: "HubSpot", color: "bg-orange-400" },
{ name: "Salesforce", color: "bg-sky-400" },
{ name: "Monday", color: "bg-red-400" },
{ name: "Notion", color: "bg-gray-300" },
{ name: "Sheets", color: "bg-green-400" },
{ name: "Slack", color: "bg-purple-400" },
{ name: "Airtable", color: "bg-cyan-400" },
{ name: "Jira", color: "bg-blue-400" },
];
function LogoBadge({ name, color }: LogoItem) {
return (
<div className="flex-shrink-0 h-14 px-6 rounded-full border border-gray-700/50 bg-gray-800/70 backdrop-blur-sm flex items-center gap-3">
<div className={`w-2.5 h-2.5 rounded-full ${color}`} />
<span className="text-gray-200 font-medium text-sm whitespace-nowrap">{name}</span>
</div>
);
}
export default function LogoCarousel({
title,
subtitle,
logos,
reverse = false,
}: {
title: string;
subtitle: string;
logos: LogoItem[];
reverse?: boolean;
}) {
const doubled = [...logos, ...logos];
return (
<section className="py-14 overflow-hidden bg-gray-950">
<div className="max-w-5xl mx-auto text-center mb-8 px-4">
<h3 className="text-xl font-semibold text-white mb-1">{title}</h3>
<p className="text-gray-500 text-sm">{subtitle}</p>
</div>
<div className="relative">
<div className="absolute left-0 top-0 bottom-0 w-32 bg-gradient-to-r from-gray-950 via-gray-950/70 to-transparent z-10 pointer-events-none" />
<div className="absolute right-0 top-0 bottom-0 w-32 bg-gradient-to-l from-gray-950 via-gray-950/70 to-transparent z-10 pointer-events-none" />
<div
className="flex gap-4 w-max"
style={{
animation: `${reverse ? "carousel-right" : "carousel-left"} 40s linear infinite`,
}}
>
{doubled.map((logo, i) => (
<LogoBadge key={i} name={logo.name} color={logo.color} />
))}
</div>
</div>
</section>
);
}

16
components/Mission.tsx Normal file
View File

@ -0,0 +1,16 @@
export default function Mission() {
return (
<section className="py-20 px-4 bg-gray-950">
<div className="max-w-4xl mx-auto">
<div className="border-glow-left bg-gray-800 rounded-xl p-8">
<h2 className="text-3xl font-bold text-white mb-4">Nasza misja</h2>
<p className="text-gray-300 text-lg leading-relaxed">
Naszą misją jest pomóc firmom wykorzystać potęgę sztucznej inteligencji.
Budujemy dedykowane agenty AI, które automatyzują procesy i zwiększają
wydajność tak, żeby ludzie mogą skupiać się na tym, co naprawdę ważne.
</p>
</div>
</div>
</section>
);
}

46
components/Nav.tsx Normal file
View File

@ -0,0 +1,46 @@
"use client";
import { useState } from "react";
import Link from "next/link";
export default function Nav() {
const [menuOpen, setMenuOpen] = useState(false);
return (
<nav className="fixed top-0 left-0 right-0 z-50 bg-gray-950/90 backdrop-blur-sm border-b border-gray-800">
<div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
<Link href="/" className="text-xl font-bold text-white text-glow">
SZMYT AI Labs
</Link>
<div className="hidden md:flex gap-8">
<Link href="/" className="text-gray-300 hover:text-cyan-400 transition-colors">Strona główna</Link>
<Link href="/oferta" className="text-gray-300 hover:text-cyan-400 transition-colors">Oferta</Link>
<Link href="/blog" className="text-gray-300 hover:text-cyan-400 transition-colors">Blog</Link>
<Link href="/about" className="text-gray-300 hover:text-cyan-400 transition-colors">O nas</Link>
<Link href="/#kontakt" className="text-gray-300 hover:text-cyan-400 transition-colors">Kontakt</Link>
</div>
<button
className="md:hidden text-gray-300"
onClick={() => setMenuOpen(!menuOpen)}
aria-label={menuOpen ? "Zamknij menu" : "Otwórz menu"}
aria-expanded={menuOpen}
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={menuOpen ? "M6 18L18 6M6 6l12 12" : "M3 6h18M3 12h18M3 18h18"} />
</svg>
</button>
</div>
{menuOpen && (
<div className="md:hidden bg-gray-950 border-t border-gray-800 px-4 py-4 flex flex-col gap-4">
<Link href="/" onClick={() => setMenuOpen(false)} className="text-gray-300 hover:text-cyan-400 transition-colors">Strona główna</Link>
<Link href="/oferta" onClick={() => setMenuOpen(false)} className="text-gray-300 hover:text-cyan-400 transition-colors">Oferta</Link>
<Link href="/blog" onClick={() => setMenuOpen(false)} className="text-gray-300 hover:text-cyan-400 transition-colors">Blog</Link>
<Link href="/about" onClick={() => setMenuOpen(false)} className="text-gray-300 hover:text-cyan-400 transition-colors">O nas</Link>
<Link href="/#kontakt" onClick={() => setMenuOpen(false)} className="text-gray-300 hover:text-cyan-400 transition-colors">Kontakt</Link>
</div>
)}
</nav>
);
}

18
components/OfertaHero.tsx Normal file
View File

@ -0,0 +1,18 @@
export default function OfertaHero() {
return (
<section className="relative py-32 px-4 pt-28 bg-gray-950">
<div className="absolute inset-0 overflow-hidden">
<div className="absolute inset-0 animate-gradient-bg" style={{ background: "linear-gradient(270deg, rgba(6,182,212,0.1), transparent 50%, rgba(139,92,246,0.07))" }} />
<div className="absolute top-0 left-1/4 w-[500px] h-[500px] bg-cyan-500/5 rounded-full blur-3xl" />
<div className="absolute top-1/3 right-1/4 w-[300px] h-[300px] bg-purple-500/5 rounded-full blur-2xl" />
</div>
<div className="relative z-10 max-w-4xl mx-auto text-center">
<p className="text-cyan-400 font-medium tracking-widest uppercase text-sm mb-4">SZMYT AI Labs</p>
<h1 className="text-5xl md:text-6xl font-bold text-white mb-4">Oferta</h1>
<p className="text-gray-400 text-xl max-w-2xl mx-auto">
Kompleksowe rozwiązania AI skrojone pod Twoją firmę
</p>
</div>
</section>
);
}

View File

@ -0,0 +1,99 @@
import ScrollReveal from "@/components/ScrollReveal";
import { SearchIcon, CpuIcon, ZapIcon, TrendingUpIcon } from "@/components/Icons";
const services = [
{
Icon: SearchIcon,
title: "Analiza Procesów Biznesowych",
description:
"Przeprowadzamy szczegółową analizę Twoich procesów biznesowych. Mapujemy przepływy danych, identyfikujemy powtarzalne zadania i wyznaczamy obszary, w których AI przyniesie największą wartość. Wynik to konkretny plan wdrożenia.",
features: [
"Mapowanie procesów end-to-end",
"Identyfikacja powtarzalnych zadań",
"Analiza kosztu vs zysk automatyzacji",
"Raport z rekomendacjami",
],
},
{
Icon: CpuIcon,
title: "Budowa Dedykowanych Agentów AI",
description:
"Projektujemy i budujemy agenty AI skrojone na potrzeby Twojej firmy. Od prostych asystentów po złożone systemy wieloagentowe — każde rozwiązanie jest tworzone od zera, nie ze standardowego szablonika.",
features: [
"Agenty dedykowane dla firmy",
"Systemy wieloagentowe",
"Integracja z LLM (GPT, Claude, Gemini)",
"Testowanie i walidacja",
],
},
{
Icon: ZapIcon,
title: "Integracja z Twoimi Narzędziami",
description:
"Podłączamy agenty AI do narzędzi, które już masz — CRM, zarządzanie projektem, komunikacja, bazy danych. Nie trzeba rezygnować z tego, co działa. AI pracuje dla Ciebie w dotychczasowym ekosystemie.",
features: [
"Integracja z CRM i ERP",
"Automatyzacja przepływów danych",
"Webhooks i API",
"Synchronizacja w czasie rzeczywistym",
],
},
{
Icon: TrendingUpIcon,
title: "Monitoring & Ciągła Optymalizacja",
description:
"Po wdrożeniu nie kończy się nasza praca. Monitorujemy wydajność agentów 24/7, analizujemy wyniki i stale poprawiamy procesy. Twoja automatyzacja ewoluuje razem z Twoim biznisem.",
features: [
"Dashboard monitoringu",
"Alerting i raportowanie",
"Kwartalny przegląd efektów",
"Iteracyjne ulepszenia",
],
},
];
export default function OfertaServices() {
return (
<section className="py-20 px-4 bg-gray-950">
<div className="max-w-4xl mx-auto">
<ScrollReveal>
<div className="text-center mb-14">
<h2 className="text-4xl font-bold text-white mb-4">Nasze usługi</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
Każde rozwiązanie jest tworzone indywidualnie dopasowane do Twojej firmy i jej celów
</p>
</div>
</ScrollReveal>
<div className="flex flex-col gap-6">
{services.map((service, i) => (
<ScrollReveal key={service.title} delay={i * 120}>
<div className="bg-gray-800 border border-gray-700 rounded-2xl p-8 hover:border-cyan-500/40 hover:shadow-lg hover:shadow-cyan-500/5 transition-all duration-300 group">
<div className="flex items-start gap-5">
<div className="w-12 h-12 flex-shrink-0 bg-cyan-500/10 rounded-xl p-3 text-cyan-400 icon-pulse">
<service.Icon />
</div>
<div className="flex-1">
<h3 className="text-xl font-semibold text-white mb-2 group-hover:text-cyan-400 transition-colors duration-300">
{service.title}
</h3>
<p className="text-gray-300 leading-relaxed mb-4">{service.description}</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
{service.features.map((f) => (
<div key={f} className="flex items-center gap-2 text-gray-400 text-sm">
<svg className="w-4 h-4 text-cyan-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span>{f}</span>
</div>
))}
</div>
</div>
</div>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,41 @@
"use client";
import { useEffect, useRef, useState } from "react";
export default function ScrollReveal({
children,
delay = 0,
}: {
children: React.ReactNode;
delay?: number;
}) {
const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
const timer = setTimeout(() => setVisible(true), delay);
observer.unobserve(el);
return () => clearTimeout(timer);
}
},
{ threshold: 0.12 }
);
observer.observe(el);
return () => observer.disconnect();
}, [delay]);
return (
<div
ref={ref}
className={`transition-all duration-700 ease-out ${
visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
}`}
>
{children}
</div>
);
}

74
components/Stats.tsx Normal file
View File

@ -0,0 +1,74 @@
"use client";
import { useEffect, useRef, useState } from "react";
const stats = [
{ value: 40, suffix: "h", label: "Oszczędności miesięczne" },
{ value: 98, suffix: "%", label: "Satysfakcja klientów" },
{ value: 3, suffix: "x", label: "Wzrost efektywności" },
{ value: 24, suffix: "/7", label: "Monitor agentów" },
];
function useCountUp(target: number, duration = 1500) {
const [count, setCount] = useState(0);
const [started, setStarted] = useState(false);
useEffect(() => {
if (!started) return;
const startTime = performance.now();
const step = (now: number) => {
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
const eased = 1 - Math.pow(1 - progress, 3);
setCount(Math.round(target * eased));
if (progress < 1) requestAnimationFrame(step);
};
requestAnimationFrame(step);
}, [started, target, duration]);
return { count, setStarted };
}
function StatCard({ value, suffix, label }: { value: number; suffix: string; label: string }) {
const ref = useRef<HTMLDivElement>(null);
const { count, setStarted } = useCountUp(value);
useEffect(() => {
const el = ref.current;
if (!el) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setStarted(true);
observer.unobserve(el);
}
},
{ threshold: 0.3 }
);
observer.observe(el);
return () => observer.disconnect();
}, [setStarted]);
return (
<div ref={ref} className="text-center px-4">
<div className="text-5xl md:text-6xl font-bold">
<span className="text-cyan-400">{count}</span>
<span className="text-cyan-300">{suffix}</span>
</div>
<p className="text-gray-400 mt-3 text-sm tracking-wide uppercase">{label}</p>
</div>
);
}
export default function Stats() {
return (
<section className="py-16 px-4 bg-gray-900 border-y border-gray-800">
<div className="max-w-4xl mx-auto">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
{stats.map((s) => (
<StatCard key={s.label} value={s.value} suffix={s.suffix} label={s.label} />
))}
</div>
</div>
</section>
);
}

33
components/Team.tsx Normal file
View File

@ -0,0 +1,33 @@
import { UserIcon } from "@/components/Icons";
export default function Team() {
const members = [
{ name: "Jan Kowalski", role: "CEO" },
{ name: "Anna Nowak", role: "CTO" },
{ name: "Piotr Wiśniewski", role: "Lead Developer" },
];
return (
<section className="py-20 px-4 bg-gray-950">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-14">
<h2 className="text-4xl font-bold text-white mb-4">Nasz zespół</h2>
<p className="text-gray-400 text-lg">Ludzie za SZMYT AI Labs</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-6 max-w-4xl mx-auto">
{members.map((m) => (
<div key={m.name} className="bg-gray-800 border border-gray-700 rounded-xl p-6 text-center">
<div className="w-24 h-24 mx-auto mb-4 rounded-full bg-gray-700 border-2 border-gray-600 flex items-center justify-center">
<div className="w-12 h-12 text-gray-500">
<UserIcon />
</div>
</div>
<h3 className="text-lg font-semibold text-white">{m.name}</h3>
<p className="text-cyan-400 text-sm mt-1">{m.role}</p>
</div>
))}
</div>
</div>
</section>
);
}

31
components/Values.tsx Normal file
View File

@ -0,0 +1,31 @@
import { LightbulbIcon, ShieldCheckIcon, ZapIcon, UsersIcon } from "@/components/Icons";
export default function Values() {
const values = [
{ Icon: LightbulbIcon, title: "Innowacja", description: "Zawsze szukamy nowoczesnych i sprawdzonych rozwiązań." },
{ Icon: ShieldCheckIcon, title: "Zaufanie", description: "Transparentność i rzetelność w każdym kroku współpracy." },
{ Icon: ZapIcon, title: "Efektywność", description: "Maksymalizujemy wyniki przy minimalnym wysiłku." },
{ Icon: UsersIcon, title: "Partnerstwo", description: "Jesteśmy Twoim partnerem — nie tylko dostawcą." },
];
return (
<section className="py-20 px-4 bg-gray-900">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-14">
<h2 className="text-4xl font-bold text-white mb-4">Nasze wartości</h2>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{values.map((v) => (
<div key={v.title} className="bg-gray-800 border border-gray-700 rounded-xl p-6 text-center hover:border-cyan-500/50 transition-colors">
<div className="w-8 h-8 text-cyan-400 mx-auto mb-4">
<v.Icon />
</div>
<h3 className="text-lg font-semibold text-white mb-2">{v.title}</h3>
<p className="text-gray-300 text-sm leading-relaxed">{v.description}</p>
</div>
))}
</div>
</div>
</section>
);
}

50
components/WhatWeDo.tsx Normal file
View File

@ -0,0 +1,50 @@
import { SearchIcon, CpuIcon, TrendingUpIcon } from "@/components/Icons";
import ScrollReveal from "@/components/ScrollReveal";
export default function WhatWeDo() {
const services = [
{
Icon: SearchIcon,
title: "Analiza procesów",
description: "Mapujemy Twoje procesy biznesowe i identyfikujemy obszary idealne do automatyzacji.",
},
{
Icon: CpuIcon,
title: "Wdrożenie agentów AI",
description: "Tworzymy i wdrażamy agenty AI w pełni dopasowane do potrzeb Twojej firmy.",
},
{
Icon: TrendingUpIcon,
title: "Monitor & Optymalizacja",
description: "Śledzi i optymalizujemy wydajność agentów w czasie rzeczywistym, non-stop.",
},
];
return (
<section className="py-20 px-4 bg-gray-950">
<div className="max-w-6xl mx-auto">
<ScrollReveal>
<div className="text-center mb-14">
<h2 className="text-4xl font-bold text-white mb-4">Co oferujemy</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
Kompleksowe rozwiązania AI dopasowane do każdej firmy
</p>
</div>
</ScrollReveal>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{services.map((s, i) => (
<ScrollReveal key={s.title} delay={i * 150}>
<div className="bg-gray-800 border border-gray-700 rounded-xl p-6 cursor-pointer hover:border-cyan-500/50 hover:-translate-y-1 hover:shadow-lg hover:shadow-cyan-500/10 transition-all duration-300 h-full">
<div className="w-8 h-8 text-cyan-400 mb-4 icon-pulse">
<s.Icon />
</div>
<h3 className="text-xl font-semibold text-white mb-2">{s.title}</h3>
<p className="text-gray-300 leading-relaxed">{s.description}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
);
}

35
components/WhyUs.tsx Normal file
View File

@ -0,0 +1,35 @@
import ScrollReveal from "@/components/ScrollReveal";
export default function WhyUs() {
const reasons = [
"Dedykowane rozwiązania dla każdej firmy — nikt nie dostanie tego samego produktu.",
"Wsparcie techniczne i merytoryczne na każdym etapie współpracy.",
"Sprawdzone technologie AI wdrożone w rzeczywistych biznesach.",
];
return (
<section className="py-20 px-4 bg-gray-950">
<div className="max-w-4xl mx-auto">
<ScrollReveal>
<div className="text-center mb-14">
<h2 className="text-4xl font-bold text-white mb-4">Dlaczego SZMYT AI Labs</h2>
</div>
</ScrollReveal>
<div className="flex flex-col gap-6">
{reasons.map((reason, i) => (
<ScrollReveal key={i} delay={i * 150}>
<div className="bg-gray-800 border border-gray-700 rounded-xl p-6 border-glow-left flex items-start gap-4 cursor-pointer hover:-translate-y-1 hover:shadow-[0_8px_30px_rgb(6,182,212,0.3)] transition-all duration-300 group">
<div className="w-8 h-8 rounded-full bg-cyan-500/20 border border-cyan-500/50 flex items-center justify-center flex-shrink-0 mt-0.5" aria-hidden="true">
<svg className="w-4 h-4 text-cyan-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<p className="text-gray-200 text-lg leading-relaxed">{reason}</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
);
}

1
data/submissions.json Normal file
View File

@ -0,0 +1 @@
[]

136
lib/blog.ts Normal file
View File

@ -0,0 +1,136 @@
import clientPromise from "./mongodb";
import { ObjectId } from "mongodb";
export interface BlogPost {
_id?: ObjectId;
title: string;
slug: string;
excerpt: string;
content: string;
author: string;
category: "case-study" | "blog";
tags: string[];
coverImage?: string;
publishedAt: Date;
updatedAt: Date;
featured: boolean;
seo?: {
title?: string;
description?: string;
keywords?: string[];
};
}
const DB_NAME = "mo1124_ai_web";
const COLLECTION_NAME = "posts";
// Helper function to serialize MongoDB documents for client components
function serializePost(post: any): BlogPost {
return {
...post,
_id: post._id?.toString(),
// Normalize author to always be a string
author:
typeof post.author === "string"
? post.author
: post.author?.name || "Unknown",
// Normalize tags to always be an array
tags: Array.isArray(post.tags)
? post.tags
: typeof post.tags === "string"
? post.tags.trim().startsWith("[")
? JSON.parse(post.tags)
: [post.tags]
: [],
publishedAt:
post.publishedAt instanceof Date
? post.publishedAt
: new Date(post.publishedAt),
updatedAt:
post.updatedAt instanceof Date
? post.updatedAt
: new Date(post.updatedAt),
};
}
export async function getAllPosts(
category?: "case-study" | "blog",
): Promise<BlogPost[]> {
try {
const client = await clientPromise;
const db = client.db(DB_NAME);
const query = category ? { category } : {};
const posts = await db
.collection<BlogPost>(COLLECTION_NAME)
.find(query)
.sort({ publishedAt: -1 })
.toArray();
return posts.map(serializePost);
} catch (error) {
console.error("Database Error:", error);
console.warn("MongoDB connection failed, returning empty posts array");
return [];
}
}
export async function getPostBySlug(slug: string): Promise<BlogPost | null> {
try {
const client = await clientPromise;
const db = client.db(DB_NAME);
const post = await db
.collection<BlogPost>(COLLECTION_NAME)
.findOne({ slug });
return post ? serializePost(post) : null;
} catch (error) {
console.error("Database Error:", error);
console.warn("MongoDB connection failed, returning null for post");
return null;
}
}
export async function getFeaturedPosts(limit: number = 3): Promise<BlogPost[]> {
try {
const client = await clientPromise;
const db = client.db(DB_NAME);
const posts = await db
.collection<BlogPost>(COLLECTION_NAME)
.find({ featured: true })
.sort({ publishedAt: -1 })
.limit(limit)
.toArray();
return posts.map(serializePost);
} catch (error) {
console.error("Database Error:", error);
console.warn("MongoDB connection failed, returning empty featured posts");
return [];
}
}
export async function getPostsByCategory(
category: "case-study" | "blog",
): Promise<BlogPost[]> {
try {
const client = await clientPromise;
const db = client.db(DB_NAME);
const posts = await db
.collection<BlogPost>(COLLECTION_NAME)
.find({ category })
.sort({ publishedAt: -1 })
.toArray();
return posts.map(serializePost);
} catch (error) {
console.error("Database Error:", error);
console.warn(
"MongoDB connection failed, returning empty posts by category",
);
return [];
}
}

21
lib/mongodb.ts Normal file
View File

@ -0,0 +1,21 @@
import { MongoClient } from "mongodb";
// Production MongoDB connection
const uri =
"mongodb://mo1124_ai_web:~4nfR5EA)3%C2%A3%40@mongo76.mydevil.net:27017/mo1124_ai_web?authSource=mo1124_ai_web";
// Use global variable to preserve connection across HMR in development
let globalWithMongo = global as typeof globalThis & {
_mongoClientPromise?: Promise<MongoClient>;
};
let clientPromise: Promise<MongoClient>;
if (!globalWithMongo._mongoClientPromise) {
const client = new MongoClient(uri);
globalWithMongo._mongoClientPromise = client.connect();
}
clientPromise = globalWithMongo._mongoClientPromise;
export default clientPromise;

37
next.config.ts Normal file
View File

@ -0,0 +1,37 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
trailingSlash: true,
output: "standalone",
// Removed output: "export" to enable API routes and ISR for blog functionality
// Force new build ID to bust cache
generateBuildId: async () => {
return `build-${Date.now()}`;
},
// Prevent nginx from caching HTML pages
async headers() {
return [
{
source: "/:path*",
headers: [
{
key: "Cache-Control",
value: "no-cache, no-store, must-revalidate",
},
{
key: "Pragma",
value: "no-cache",
},
{
key: "Expires",
value: "0",
},
],
},
];
},
};
export default nextConfig;

2355
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "aiagentdlafirm",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p 56693 -H localhost",
"seed:blog": "tsx scripts/seed-blog.ts"
},
"dependencies": {
"mongodb": "^7.1.0",
"next": "16.1.6",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"tailwindcss": "^4",
"tsx": "^4.21.0",
"typescript": "^5"
}
}

7
postcss.config.mjs Normal file
View File

@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;

15
public/.htaccess Normal file
View File

@ -0,0 +1,15 @@
# Cache static assets
<FilesMatch "\.(jpg|jpeg|png|gif|svg|webp|ico|css|js|woff|woff2|ttf|eot)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
# Cache HTML with short lifetime
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "public, max-age=3600, must-revalidate"
</FilesMatch>
# Security headers
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

4
public/favicon.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
<rect width="32" height="32" rx="6" fill="#030712"/>
<text x="16" y="23" text-anchor="middle" font-family="Arial, sans-serif" font-weight="bold" font-size="22" fill="#06b6d4">S</text>
</svg>

After

Width:  |  Height:  |  Size: 279 B

BIN
public/og-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

5
public/robots.txt Normal file
View File

@ -0,0 +1,5 @@
User-agent: *
Allow: /
Disallow: /api/
Sitemap: https://sztucznainteligencjadlafirm.pl/sitemap.xml

229
scripts/seed-blog.ts Normal file
View File

@ -0,0 +1,229 @@
import clientPromise from "@/lib/mongodb";
const samplePosts = [
{
title: "Jak AI może zautomatyzować obsługę klienta w e-commerce",
slug: "ai-obsluga-klienta-ecommerce",
excerpt:
"Dowiedz się jak agenty AI mogą odpowiadać na 80% zapytań klientów 24/7, skracając czas odpowiedzi z godzin do sekund.",
content: `
<h2>Wyzwanie: Zalewające zapytania klientów</h2>
<p>Sklepy e-commerce otrzymują setki zapytań dziennie: "Kiedy dostanę paczkę?", "Jak zwrócić produkt?", "Czy macie rozmiar XL?".</p>
<h2>Rozwiązanie: AI Agent obsługi klienta</h2>
<p>Agent AI może:</p>
<ul>
<li>Odpowiadać na FAQ w czasie rzeczywistym</li>
<li>Sprawdzać status zamówień w systemie</li>
<li>Inicjować zwroty i reklamacje</li>
<li>Przekazywać złożone sprawy do człowieka</li>
</ul>
<h2>Efekty</h2>
<p>Nasi klienci z e-commerce widzą:</p>
<ul>
<li><strong>80% automatyzacji</strong> - większość zapytań obsługiwana bez człowieka</li>
<li><strong>Czas odpowiedzi: &lt;10 sekund</strong> - zamiast kilku godzin</li>
<li><strong>Zadowolenie klientów: +35%</strong> - szybsze odpowiedzi = szczęśliwsi klienci</li>
</ul>
<h2>Implementacja</h2>
<p>Wdrożenie zajmuje 2-3 tygodnie:</p>
<ol>
<li>Analiza najczęstszych zapytań</li>
<li>Integracja z systemem zamówień</li>
<li>Trening AI na historycznych rozmowach</li>
<li>Testowanie i deploy</li>
</ol>
<p><strong>Zainteresowany?</strong> <a href="/#kontakt">Skontaktuj się z nami</a> po bezpłatną konsultację.</p>
`,
author: "Adrian Miesikowski",
category: "case-study",
tags: ["e-commerce", "obsługa klienta", "automatyzacja", "chatbot"],
coverImage: "/blog/ecommerce-ai.jpg",
publishedAt: new Date("2026-01-15"),
updatedAt: new Date("2026-01-15"),
featured: true,
seo: {
title: "AI w obsłudze klienta e-commerce - Case Study | SZMYT AI Labs",
description:
"Zobacz jak AI agent zautomatyzował 80% obsługi klienta w sklepie e-commerce. Czas odpowiedzi spadł z godzin do 10 sekund.",
keywords: [
"AI e-commerce",
"chatbot obsługa klienta",
"automatyzacja e-commerce",
"AI customer service",
],
},
},
{
title: "5 procesów biznesowych idealnych do automatyzacji AI w 2026",
slug: "5-procesow-do-automatyzacji-ai",
excerpt:
"Nie każdy proces nadaje się do automatyzacji AI. Sprawdź 5 obszarów, gdzie AI przynosi największy ROI.",
content: `
<h2>Wprowadzenie</h2>
<p>AI to potężne narzędzie, ale nie do wszystkiego. Oto 5 procesów, gdzie automatyzacja AI ma największy sens biznesowy:</p>
<h2>1. Obsługa zapytań klientów (Customer Support)</h2>
<p><strong>Dlaczego:</strong> Powtarzalne pytania, 24/7 availability, skalowalność</p>
<p><strong>ROI:</strong> 60-80% redukcja kosztów obsługi</p>
<h2>2. Analiza dokumentów i faktur</h2>
<p><strong>Dlaczego:</strong> Czasochłonne, podatne na błędy ludzkie, strukturalne dane</p>
<p><strong>ROI:</strong> 90% redukcja czasu przetwarzania</p>
<h2>3. Kwalifikacja leadów (Lead Scoring)</h2>
<p><strong>Dlaczego:</strong> AI analizuje setki sygnałów szybciej niż człowiek</p>
<p><strong>ROI:</strong> +40% konwersja leadów na klientów</p>
<h2>4. Content generation dla e-commerce</h2>
<p><strong>Dlaczego:</strong> Opisy produktów, SEO content, email marketing</p>
<p><strong>ROI:</strong> 10x szybsza produkcja contentu</p>
<h2>5. Monitoring i alerty</h2>
<p><strong>Dlaczego:</strong> AI wykrywa anomalie i przewiduje problemy</p>
<p><strong>ROI:</strong> Zapobieganie przestojom = miliony oszczędności</p>
<h2>Jak zacząć?</h2>
<ol>
<li>Wybierz 1 proces z listy</li>
<li>Zmierz current state (czas, koszt, błędy)</li>
<li>Pilot z AI na małą skalę</li>
<li>Mierz rezultaty i skaluj</li>
</ol>
<p><a href="/#kontakt">Umów bezpłatną konsultację</a> - pomożemy wybrać najlepszy proces do automatyzacji w Twojej firmie.</p>
`,
author: "SZMYT AI Labs Team",
category: "blog",
tags: ["automatyzacja", "AI w biznesie", "ROI", "strategie AI"],
publishedAt: new Date("2026-01-20"),
updatedAt: new Date("2026-01-20"),
featured: true,
seo: {
title:
"5 procesów biznesowych do automatyzacji AI w 2026 | SZMYT AI Labs",
description:
"Dowiedz się które procesy biznesowe przynoszą największy ROI z automatyzacji AI. Praktyczny przewodnik z case studies.",
keywords: [
"automatyzacja AI",
"procesy biznesowe",
"AI ROI",
"AI w firmie",
],
},
},
{
title: "Jak zintegrowaliśmy AI z Salesforce dla firmy logistycznej",
slug: "integracja-ai-salesforce-logistyka",
excerpt:
"Case study: AI agent automatyzujący wprowadzanie leadów do Salesforce skrócił proces z 15 minut do 30 sekund.",
content: `
<h2>Klient: Firma logistyczna, 200+ pracowników</h2>
<h2>Problem</h2>
<p>Sales team otrzymywał zapytania ofertowe emailem i ręcznie przepisywał dane do Salesforce:</p>
<ul>
<li>15-20 minut na jedno zapytanie</li>
<li>50-70 zapytań dziennie</li>
<li>Błędy w przepisywaniu danych</li>
<li>Opóźnienia w odpowiedziach</li>
</ul>
<h2>Rozwiązanie: AI Agent + Salesforce Integration</h2>
<p>Stworzyliśmy agenta AI który:</p>
<ol>
<li>Monitoruje skrzynkę zapytań ofertowych</li>
<li>Ekstrahuje kluczowe informacje (trasa, waga, termin)</li>
<li>Automatycznie tworzy Lead w Salesforce</li>
<li>Kategoryzuje i scoruje lead</li>
<li>Notyfikuje odpowiedniego sales repa</li>
</ol>
<h2>Architektura</h2>
<pre><code>Email AI Parser Salesforce API Slack Notification</code></pre>
<h2>Technologie</h2>
<ul>
<li>Claude 3.5 Sonnet (extraction)</li>
<li>Salesforce REST API</li>
<li>Gmail API</li>
<li>Slack Webhooks</li>
</ul>
<h2>Rezultaty po 3 miesiącach</h2>
<table>
<tr><th>Metryka</th><th>Przed</th><th>Po</th><th>Zmiana</th></tr>
<tr><td>Czas przetwarzania</td><td>15 min</td><td>30 sek</td><td>-96%</td></tr>
<tr><td>Błędy w danych</td><td>12%</td><td>0.5%</td><td>-96%</td></tr>
<tr><td>Leadów/dzień</td><td>50</td><td>120</td><td>+140%</td></tr>
<tr><td>Konwersja</td><td>22%</td><td>31%</td><td>+41%</td></tr>
</table>
<h2>ROI</h2>
<p><strong>Oszczędności:</strong> 12.5 godziny/dzień × 20 dni × 150 PLN/h = <strong>37,500 PLN/miesiąc</strong></p>
<p><strong>Koszt wdrożenia:</strong> 25,000 PLN (one-time) + 2,000 PLN/miesiąc (utrzymanie)</p>
<p><strong>Payback period:</strong> &lt;1 miesiąc</p>
<h2>Lessons Learned</h2>
<ul>
<li>AI nie musi być perfekcyjne - 99.5% accuracy wystarczy</li>
<li>Integracja z istniejącymi narzędziami &gt; nowe platformy</li>
<li>Human-in-the-loop dla edge cases jest OK</li>
</ul>
<p><strong>Podobne wyzwanie?</strong> <a href="/#kontakt">Napisz do nas</a> - pokażemy jak możemy pomóc.</p>
`,
author: "Adrian Miesikowski",
category: "case-study",
tags: ["Salesforce", "integracja", "logistyka", "email automation"],
coverImage: "/blog/salesforce-integration.jpg",
publishedAt: new Date("2026-01-10"),
updatedAt: new Date("2026-01-10"),
featured: false,
seo: {
title:
"Integracja AI z Salesforce - Case Study Logistyka | SZMYT AI Labs",
description:
"Jak AI agent skrócił proces wprowadzania leadów do Salesforce z 15 minut do 30 sekund. ROI w miesiąc.",
keywords: [
"Salesforce AI",
"automatyzacja CRM",
"AI logistyka",
"integracja Salesforce",
],
},
},
];
async function seed() {
try {
console.log("🌱 Łączenie z MongoDB...");
const client = await clientPromise;
const db = client.db("mo1124_ai_web");
const collection = db.collection("posts");
console.log("🗑️ Czyszczenie istniejących postów...");
await collection.deleteMany({});
console.log("📝 Dodawanie przykładowych postów...");
const result = await collection.insertMany(samplePosts);
console.log(`✅ Dodano ${result.insertedCount} postów do bazy!`);
console.log("\n📊 Posty:");
samplePosts.forEach((post, i) => {
console.log(`${i + 1}. [${post.category}] ${post.title}`);
console.log(` URL: /blog/${post.slug}`);
});
console.log("\n🎉 Seed completed!");
process.exit(0);
} catch (error) {
console.error("❌ Błąd podczas seed:", error);
process.exit(1);
}
}
seed();

34
tsconfig.json Normal file
View File

@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}