diff --git a/app/page.tsx b/app/page.tsx index ab65e92..7e766bf 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,6 +1,12 @@ 'use client' -import { motion, AnimatePresence } from 'framer-motion' +import { motion, AnimatePresence, useScroll, useTransform, useMotionTemplate, useTime, MotionValue, useSpring } from "framer-motion"; + import { useState, useCallback, useEffect } from "react" +import { Palette, Sparkles, Gauge, FlaskConical, TrendingUp, Users, Brain, CheckCircle2, Zap, CircleDot, XCircle } from "lucide-react"; +// na górze pliku (masz już useEffect), dodaj: +import { createPortal } from "react-dom"; + + export default function Home() { @@ -8,6 +14,10 @@ export default function Home() { const [activeSection, setActiveSection] = useState("PrimeCode"); + const [uiVariant, setUiVariant] = useState<"A" | "B" | "C">("A"); + // A = Vibrant, B = Editorial, C = Dark + + useEffect(() => { const sections = document.querySelectorAll("section[id]"); const observer = new IntersectionObserver( @@ -79,6 +89,42 @@ export default function Home() { } ] + // --- Wspólna treść dla wszystkich wariantów sekcji "DlaczegoIntegracji" --- + const why = { + p1: ( + <> + 76% konsumentów oczekuje, że marka będzie + przewidywać ich potrzeby, nie tylko reagować + (Salesforce, 2023). + + ), + p2: ( + <> + Pokolenie Z nie buduje lojalności przez reklamy. + Buduje ją przez wartość, użyteczność i autentyczność. + Aż 65% młodych konsumentów deklaruje, + że lojalność wobec marki zależy od spójnych i realnych doświadczeń + (McKinsey, 2023). + + ), + bulletsIntro: "Marka nie żyje w kampaniach. Żyje w:", + bullets: [ + "chatbotach, landingach, mailach i pushach,", + "procesach sprzedażowych i onboardingowych,", + "sposobie, w jaki działa Twój model cenowy, UX i obsługa klienta.", + ], + p3: ( + <> + Jeśli to wszystko nie gra razem, marka traci moc. +
+ I traci klientów. + Według badania PwC aż 32% klientów porzuca markę po jednej + złej interakcji, nawet jeśli wcześniej byli zadowoleni. + + ), + }; + + const [expandedIndex, setExpandedIndex] = useState(null); // === NOWE tiles (podmień całą dotychczasową definicję) === @@ -180,47 +226,10 @@ export default function Home() { -
+
- {/* ---- ESTETYCZNE, WIELOWARSTWOWE TŁO ---- */} -
- {/* Gradient bazowy */} -
+ - {/* Winieta dla lepszej głębi */} -
- - {/* Duży, miękki blob lewy-górny */} - - - {/* Duży, miękki blob prawy-dolny */} - - - {/* Centralny blob dla balansu */} - - - {/* Tekstura (grain) */} -
-
{/* Sticky Navbar */}
+ {/* STYLE SWITCHER – pływający panel */} + +
) } @@ -1246,5 +1279,458 @@ function Tile({ ); } +// KOMPONENT PRZEŁĄCZNIKA (wrzuć pod innymi komponentami w tym pliku) +function StyleSwitcher({ + value, + onChange, +}: { + value: "A" | "B" | "C"; + onChange: (v: "A" | "B" | "C") => void; +}) { + const [mounted, setMounted] = useState(false); + useEffect(() => setMounted(true), []); + if (!mounted) return null; + + return createPortal( +
+
+
+ + Wariant +
+
+ {(["A", "B", "C"] as const).map((v) => ( + + ))} +
+
+
, + document.body + ); +} +function DotList({ items, className = "" }: { items: string[]; className?: string }) { + return ( +
    + {items.map((txt, i) => ( +
  • + {/* ta sama turkusowa kropka co w innych wypunktowaniach */} +
  • + ))} +
+ ); +} + + + +function DlaczegoIntegracji_Timeline({ + why, +}: { + why: { + p1: React.ReactNode; + p2: React.ReactNode; + bulletsIntro: string; + bullets: string[]; + p3: React.ReactNode; + }; +}) { + return ( +
+
+ {/* Nagłówek */} + + Dlaczego integracja marki to konieczność? + +
+ + {/* Oś czasu */} +
+ {/* pionowa linia */} +
+ ); +} + + +function Background({ variant }: { variant: "A" | "B" | "C" }) { + const [reduce, setReduce] = useState(false); + useEffect(() => { + setReduce(window.matchMedia("(prefers-reduced-motion: reduce)").matches); + }, []); + return ( +
+ {/* WARSTWA BAZOWA – jak na początku strony */} +
+ + {/* === A — Aurora (oryginalna kolorystyka) === */} + {variant === "A" && ( + <> + + + + + )} + + {/* === B — Editorial (pasy + shine) === */} + {variant === "B" && ( + <> +
+
+ {!reduce && ( + + )} + + )} + + {/* === C — Kinetic Grid + SCROLL-REACTIVE AURORA === */} + {variant === "C" && ( + <> + + + + )} + + + + + + {/* Ziarno (delikatne) */} +
+
+ ); +} + + + + + +type ToneOpts = { wobbleSpeed?: number; wobbleAmpDeg?: number }; + +// PASTELOWE, JESZCZE JAŚNIEJSZE ODCIENIE +// start: bardzo jasny błękit, end: bardzo jasny morelowy +const START = { h: 208, s: 78, l: 96 }; // hsl(208 78% 96%) +const END = { h: 24 + 360, s: 82, l: 94 }; // 24° + 360° => unikamy zieleni + +function useBrandTone({ wobbleSpeed = 0.001, wobbleAmpDeg = 0.2 }: ToneOpts = {}) { + const { scrollYProgress } = useScroll(); + const time = useTime() as MotionValue; + + // SINGLE SWEEP: 0 -> 1 tylko raz + const phase = useSpring(scrollYProgress, { stiffness: 35, damping: 22, mass: 0.9 }); + + // H, S, L płynnie z START -> END (hue idzie po zegarze 208 -> 384) + const hBase = useTransform(phase, [0, 1], [START.h, END.h]); + const sBase = useTransform(phase, [0, 1], [START.s, END.s]); + const lBase = useTransform(phase, [0, 1], [START.l, END.l]); + + // Bardzo subtelny „oddech” hue, żeby tło żyło, ale bez mrygania + const wobbleRaw = useTransform(time, t => Math.sin(t * wobbleSpeed * 1000) * wobbleAmpDeg); + const wobble = useSpring(wobbleRaw, { stiffness: 60, damping: 20 }); + + // top = baza + leciutki wobble (ułamki stopnia) + const hTop = useTransform([hBase, wobble] as MotionValue[], (vals: number[]) => { + const [h, w] = vals as [number, number]; + return h + w; // hue może przekraczać 360° – CSS to normalizuje + }); + const sTop = sBase; + const lTop = lBase; + + // dolna warstwa: odrobinkę mniej nasycona i ciut ciemniejsza (wciąż pastel) + const hBot = useTransform(hTop, v => v - 4); + const sBot = useTransform(sTop, v => Math.max(65, v - 8)); + const lBot = useTransform(lTop, v => Math.max(88, v - 4)); + + // dwa środki – zawsze kilka odcieni, ale „kolor przewodni” zmienia się tylko raz + const mix2 = (a: MotionValue, b: MotionValue, wa: number) => + useTransform([a, b] as MotionValue[], (vals: number[]) => { + const [x, y] = vals as [number, number]; + return x * wa + y * (1 - wa); + }); + + const hMid1 = mix2(hTop, hBot, 0.65); + const sMid1 = mix2(sTop, sBot, 0.65); + const lMid1 = mix2(lTop, lBot, 0.65); + + const hMid2 = useTransform([hTop, hBot, wobble] as MotionValue[], (vals: number[]) => { + const [a, b, w] = vals as [number, number, number]; + return a * 0.35 + b * 0.65 + w * 0.15; + }); + const sMid2 = mix2(sTop, sBot, 0.35); + const lMid2 = mix2(lTop, lBot, 0.35); + + // kolory jako CSS-zmienne (bez migotania) + const c1 = useMotionTemplate`hsl(${hTop} ${sTop}% ${lTop}%)`; + const c2 = useMotionTemplate`hsl(${hMid1} ${sMid1}% ${lMid1}%)`; + const c3 = useMotionTemplate`hsl(${hMid2} ${sMid2}% ${lMid2}%)`; + const c4 = useMotionTemplate`hsl(${hBot} ${sBot}% ${lBot}%)`; + + const accent = useMotionTemplate`hsl(${hBot} ${sBot}% calc(${lBot} - 10%))`; + const accentSoft = useMotionTemplate`hsl(${hBot} ${sBot}% calc(${lBot} - 10%) / .45)`; + const gridTint = useMotionTemplate`hsl(${hTop} ${sTop}% 46% / .16)`; + + // ⬇⬇⬇ DODAJ scrollYProgress do return + return { scrollYProgress, c1, c2, c3, c4, accent, accentSoft, gridTint }; +} + +function ScrollToneBackground() { + const { c1, c2, c3, c4 } = useBrandTone(); + + return ( + + ); +} + +function ScrollToneDecor({ reduce = false }: { reduce?: boolean }) { + const { scrollYProgress, accent, accentSoft, gridTint } = useBrandTone(); + const time = useTime() as MotionValue; + + const x1 = useTransform(scrollYProgress, [0, 1], [15, 70]); + const y1 = useTransform(scrollYProgress, [0, 1], [18, 34]); + const x2 = useTransform(scrollYProgress, [0, 1], [85, 28]); + const y2 = useTransform(scrollYProgress, [0, 1], [78, 62]); + + const wobRaw = useTransform(time, t => Math.sin(t * 0.0016) * 4); + const wob = useSpring(wobRaw, { stiffness: 60, damping: 18 }); + + const orb1 = useMotionTemplate` + radial-gradient(880px 880px at calc(${x1}% + ${wob}) ${y1}%, + ${accentSoft}, transparent 60%)`; + const orb2 = useMotionTemplate` + radial-gradient(1040px 1040px at ${x2}% calc(${y2}% + ${wob}), + ${accentSoft}, transparent 58%)`; + + const shineX = useSpring( + useTransform(scrollYProgress, [0, 1], ["-130%", "130%"]), + { stiffness: 60, damping: 20 } + ); + const shineBg = useMotionTemplate`linear-gradient(90deg, transparent, ${accentSoft}, transparent)`; + + const spin = useTransform(time, t => (t * 0.012) % 360); + const rings = useMotionTemplate` + conic-gradient(from 0deg, + transparent 0deg, ${accentSoft} 24deg, transparent 48deg, + ${accentSoft} 72deg, transparent 96deg, ${accentSoft} 120deg, transparent 360deg)`; + + const gridImg = useMotionTemplate` + repeating-linear-gradient(0deg, transparent, transparent 23px, ${gridTint} 24px), + repeating-linear-gradient(90deg, transparent, transparent 23px, ${gridTint} 24px)`; + + return ( + <> + + + + {!reduce && ( + + )} + + + + + ); +} \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index 2978fd3..0feadb4 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,8 +1,12 @@ import type { NextConfig } from "next"; -const nextConfig: NextConfig = { - /* config options here */ - output: 'export', +// next.config.ts +const nextConfig = { + output: "export", + images: { unoptimized: true }, + trailingSlash: true, + eslint: { ignoreDuringBuilds: true }, // ← nie blokuj buildu na lint + // typescript: { ignoreBuildErrors: true }, // ← użyj tylko awaryjnie }; - export default nextConfig; + diff --git a/out.rar b/out.rar new file mode 100644 index 0000000..36b4683 Binary files /dev/null and b/out.rar differ diff --git a/out.zip b/out.zip index 9d0b349..45932c1 100644 Binary files a/out.zip and b/out.zip differ diff --git a/package-lock.json b/package-lock.json index c57935c..fc3b3d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "framer-motion": "^12.23.11", + "lucide-react": "^0.541.0", "next": "15.4.4", "react": "19.1.0", "react-dom": "19.1.0" @@ -4520,6 +4521,15 @@ "loose-envify": "cli.js" } }, + "node_modules/lucide-react": { + "version": "0.541.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.541.0.tgz", + "integrity": "sha512-s0Vircsu5WaGv2KoJZ5+SoxiAJ3UXV5KqEM3eIFDHaHkcLIFdIWgXtZ412+Gh02UsdS7Was+jvEpBvPCWQISlg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", diff --git a/package.json b/package.json index 367b64a..c67df1e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "framer-motion": "^12.23.11", + "lucide-react": "^0.541.0", "next": "15.4.4", "react": "19.1.0", "react-dom": "19.1.0" @@ -26,4 +27,4 @@ "tailwindcss": "^4", "typescript": "^5" } -} \ No newline at end of file +}