commit 5bc48de89021f53b203e24e17ff2e0cf512d727d Author: vitaliimulika-dev Date: Thu Jan 15 14:39:55 2026 +0200 Initial commit diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..02269f0 --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +DISABLE_ESLINT_PLUGIN=true diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..8687ee0 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,62 @@ +name: Build + +on: + workflow_dispatch: + inputs: + branch: + description: 'Branch to build' + required: true + default: 'main' + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout branch + uses: actions/checkout@v3 + with: + ref: ${{ gitea.event.inputs.branch }} + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 24 + + - name: Install dependencies + run: | + set -euo pipefail + npm install --no-audit --silent 2>&1 | tee install.log + env: + NODE_OPTIONS: '--max-old-space-size=4096' + + - name: Build (react-scripts build) + env: + CI: 'false' + NODE_OPTIONS: '--max-old-space-size=4096' + run: | + set -euo pipefail + npm run build 2>&1 | tee build.log + timeout-minutes: 5 + + - name: Verify build folder exists + run: test -d build || (echo "No build folder. Check build logs above."; exit 1) + + - name: Upload logs on failure + if: failure() + uses: actions/upload-artifact@v3 + with: + name: build-logs + path: | + install.log + build.log + npm-debug.log* + if-no-files-found: ignore + + - name: Build completed + if: success() + run: echo "Build completed successfully" diff --git a/package.json b/package.json new file mode 100644 index 0000000..74276b0 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "nestjs-website", + "version": "0.1.0", + "private": true, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-scripts": "^5.0.1", + "lucide-react": "^0.400.0", + "framer-motion": "^11.0.0" + }, + "devDependencies": { + "tailwindcss": "^3.4.0", + "postcss": "^8.4.0", + "autoprefixer": "^10.4.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..96bb01e --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..3bc5fdf --- /dev/null +++ b/public/index.html @@ -0,0 +1,1235 @@ + + + + + + + + + + + + NestJS - A progressive Node.js framework + + + +
+ + + + + \ No newline at end of file diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..b2e8c1e --- /dev/null +++ b/src/App.js @@ -0,0 +1,32 @@ +import React from 'react'; +import Header from './components/Header'; +import Hero from './components/Hero'; +import Features from './components/Features'; +import EverythingYouNeed from './components/EverythingYouNeed'; +import DeploySection from './components/DeploySection'; +import CoursesSection from './components/CoursesSection'; +import EnterpriseSection from './components/EnterpriseSection'; +import LivePreview from './components/LivePreview'; +import SupportSection from './components/SupportSection'; +import Newsletter from './components/Newsletter'; +import Footer from './components/Footer'; + +function App() { + return ( +
+
+ + + + + + + + + +
+
+ ); +} + +export default App; \ No newline at end of file diff --git a/src/components/CoursesSection.js b/src/components/CoursesSection.js new file mode 100644 index 0000000..06ff357 --- /dev/null +++ b/src/components/CoursesSection.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const CoursesSection = () => { + const shouldReduceMotion = useReducedMotion(); + + if (shouldReduceMotion) { + return ( +
+
+
+

+ Official NestJS Courses +

+

+ Learn everything you need to master NestJS and tackle modern backend applications at any scale. +

+ +
+
+
+ ); + } + + return ( +
+
+ +

+ Official NestJS Courses +

+

+ Learn everything you need to master NestJS and tackle modern backend applications at any scale. +

+ +
+
+
+ ); +}; + +export default CoursesSection; \ No newline at end of file diff --git a/src/components/DeploySection.js b/src/components/DeploySection.js new file mode 100644 index 0000000..7fbd5d7 --- /dev/null +++ b/src/components/DeploySection.js @@ -0,0 +1,83 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const DeploySection = () => { + const shouldReduceMotion = useReducedMotion(); + + if (shouldReduceMotion) { + return ( +
+
+
+ {/* Deploy Card */} +
+

Deploy, mau!

+

+ Provision and manage your infrastracture on AWS without the hassle and extra DevOps work. +

+ +
+ + {/* Explore Graph Card */} +
+

Explore your graph

+

+ Identify dependencies and connections between modules, and dive deep into the inner workings of your classes. +

+ +
+
+
+
+ ); + } + + return ( +
+
+
+ {/* Deploy Card */} + +

Deploy, mau!

+

+ Provision and manage your infrastracture on AWS without the hassle and extra DevOps work. +

+ +
+ + {/* Explore Graph Card */} + +

Explore your graph

+

+ Identify dependencies and connections between modules, and dive deep into the inner workings of your classes. +

+ +
+
+
+
+ ); +}; + +export default DeploySection; \ No newline at end of file diff --git a/src/components/EnterpriseSection.js b/src/components/EnterpriseSection.js new file mode 100644 index 0000000..8716d01 --- /dev/null +++ b/src/components/EnterpriseSection.js @@ -0,0 +1,67 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const EnterpriseSection = () => { + const shouldReduceMotion = useReducedMotion(); + + if (shouldReduceMotion) { + return ( +
+
+
+
+

+ The open source platform designed for the future. Build enterprise. +

+

+ A complete development kit for building scalable server-side apps. Contact us to find out more about expertise consulting, on-site enterprise support, trainings, and private sessions. +

+ +
+
+
+ ); + } + + return ( + +
+
+
+ + The open source platform designed for the future. Build enterprise. + + + A complete development kit for building scalable server-side apps. Contact us to find out more about expertise consulting, on-site enterprise support, trainings, and private sessions. + + + Learn more about support offerings + +
+
+
+ ); +}; + +export default EnterpriseSection; \ No newline at end of file diff --git a/src/components/EverythingYouNeed.js b/src/components/EverythingYouNeed.js new file mode 100644 index 0000000..6f5af14 --- /dev/null +++ b/src/components/EverythingYouNeed.js @@ -0,0 +1,121 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const EverythingYouNeed = () => { + const shouldReduceMotion = useReducedMotion(); + + const features = [ + { + title: "MODULARITY", + description: "Streamline upkeep by organizing applications into self-contained modules.", + icon: "https://nestjs.com/puzzle.c9dfc495.svg" + }, + { + title: "SCALABILITY", + description: "Scale seamlessly with efficient, battle-tested components.", + icon: "https://nestjs.com/rocket.518dadfa.svg" + }, + { + title: "DEPENDENCY INJECTION", + description: "Elevate testability with a sophisticated dependency injection system.", + icon: "https://nestjs.com/di.a0b12f44.svg" + }, + { + title: "TYPE SAFETY", + description: "Mitigate errors through the robust type safety features of TypeScript.", + icon: "https://nestjs.com/type-safety.34453790.svg" + }, + { + title: "RICH ECOSYSTEM", + description: "Explore a rich ecosystem offering versatile tools to craft solutions tailored to your needs.", + icon: "https://nestjs.com/ecosystem.eaa69289.svg" + }, + { + title: "ENTERPRISE-READY", + description: "Trusted by thousands of leading companies and organizations worldwide.", + icon: "https://nestjs.com/chip.3b61cda8.svg" + }, + { + title: "MICROSERVICES", + description: "Create loosely coupled, independently deployable services for increased agility and scalability.", + icon: "https://nestjs.com/microservices.e0074903.svg" + }, + { + title: "WEB APPS", + description: "Build REST APIs, GraphQL APIs, Queues, and real-time & event-driven applications in no time.", + icon: "https://nestjs.com/api.67807f71.svg" + } + ]; + + if (shouldReduceMotion) { + return ( +
+
+
+

+ Everything you need.. +

+

+ Build robust, powerful, and scalable server-side applications and stop reinventing the wheel. +

+
+ +
+ {features.map((feature, index) => ( +
+
+ +
+

{feature.title}

+

{feature.description}

+
+ ))} +
+
+
+ ); + } + + return ( +
+
+ +

+ Everything you need.. +

+

+ Build robust, powerful, and scalable server-side applications and stop reinventing the wheel. +

+
+ +
+ {features.map((feature, index) => ( + +
+ +
+

{feature.title}

+

{feature.description}

+
+ ))} +
+
+
+ ); +}; + +export default EverythingYouNeed; \ No newline at end of file diff --git a/src/components/Features.js b/src/components/Features.js new file mode 100644 index 0000000..d3ad6e1 --- /dev/null +++ b/src/components/Features.js @@ -0,0 +1,75 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const Features = () => { + const shouldReduceMotion = useReducedMotion(); + + const features = [ + { + title: "EXTENSIBLE", + description: "Provides unparalleled flexibility through its meticulously crafted modular architecture.", + icon: "https://nestjs.com/3d.cfabe065.svg" + }, + { + title: "VERSATILE", + description: "Serves as a robust, elegant, and well-structured foundation for all kinds of server-side applications.", + icon: "https://nestjs.com/magic-wand.ff01fe1d.svg" + }, + { + title: "PROGRESSIVE", + description: "Introduces design patterns and well-established solutions to the Node.js landscape.", + icon: "https://nestjs.com/quality.d1d04ce8.svg" + } + ]; + + if (shouldReduceMotion) { + return ( +
+
+
+ {features.map((feature, index) => ( +
+
+ +
+

{feature.title}

+

{feature.description}

+
+ ))} +
+
+
+ ); + } + + return ( +
+
+
+ {features.map((feature, index) => ( + +
+ +
+

{feature.title}

+

{feature.description}

+
+ ))} +
+
+
+ ); +}; + +export default Features; \ No newline at end of file diff --git a/src/components/Footer.js b/src/components/Footer.js new file mode 100644 index 0000000..052d9fe --- /dev/null +++ b/src/components/Footer.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { Github, X, Linkedin } from 'lucide-react'; + +const Footer = () => { + return ( + + ); +}; + +export default Footer; \ No newline at end of file diff --git a/src/components/Header.js b/src/components/Header.js new file mode 100644 index 0000000..72c212a --- /dev/null +++ b/src/components/Header.js @@ -0,0 +1,87 @@ +import React, { useState } from 'react'; +import { Menu, X, ChevronDown, Github } from 'lucide-react'; + +const Header = () => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + const [isResourcesOpen, setIsResourcesOpen] = useState(false); + + return ( +
+
+
+ {/* Logo */} +
+ + NestJS - A progressive Node.js framework + +
+ + {/* Desktop Navigation */} + + + {/* Social Links */} +
+ + + + + + + + + +
+ + {/* Mobile menu button */} + +
+ + {/* Mobile Navigation */} + {isMenuOpen && ( +
+
+ + DOCUMENTATION + + + ENTERPRISE + + + NEW + RESOURCES + +
+
+ )} +
+
+ ); +}; + +export default Header; \ No newline at end of file diff --git a/src/components/Hero.js b/src/components/Hero.js new file mode 100644 index 0000000..7714312 --- /dev/null +++ b/src/components/Hero.js @@ -0,0 +1,80 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; +import { Github } from 'lucide-react'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const Hero = () => { + const shouldReduceMotion = useReducedMotion(); + + if (shouldReduceMotion) { + return ( +
+
+
+
+

+ Hello, nest! +

+

+ A progressive Node.js framework for building efficient, reliable and scalable server-side applications. +

+
+ + +
+
+
+
+ ); + } + + return ( + +
+
+
+ + Hello, nest! + + + A progressive Node.js framework for building efficient, reliable and scalable server-side applications. + + + + + +
+
+
+ ); +}; + +export default Hero; \ No newline at end of file diff --git a/src/components/LivePreview.js b/src/components/LivePreview.js new file mode 100644 index 0000000..519e1e7 --- /dev/null +++ b/src/components/LivePreview.js @@ -0,0 +1,47 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const LivePreview = () => { + const shouldReduceMotion = useReducedMotion(); + + if (shouldReduceMotion) { + return ( +
+
+

Live preview

+

+ See how your application may potentially look like without leaving your personal browser. +

+
+
+ ); + } + + return ( +
+
+ + Live preview + + + See how your application may potentially look like without leaving your personal browser. + +
+
+ ); +}; + +export default LivePreview; \ No newline at end of file diff --git a/src/components/Newsletter.js b/src/components/Newsletter.js new file mode 100644 index 0000000..723af3c --- /dev/null +++ b/src/components/Newsletter.js @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; +import { Send } from 'lucide-react'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const Newsletter = () => { + const [email, setEmail] = useState(''); + const shouldReduceMotion = useReducedMotion(); + + const handleSubmit = (e) => { + e.preventDefault(); + // Handle newsletter subscription + console.log('Newsletter subscription:', email); + }; + + if (shouldReduceMotion) { + return ( +
+
+

Join our Newsletter

+

+ Subscribe to stay up to date with the latest Nest updates, features, and videos! +

+
+ setEmail(e.target.value)} + placeholder="Enter your email" + className="flex-1 px-4 py-3 border border-nest-border rounded-full focus:outline-none focus:border-nest-red" + required + /> + +
+
+
+ ); + } + + return ( +
+
+ + Join our Newsletter + + + Subscribe to stay up to date with the latest Nest updates, features, and videos! + + + setEmail(e.target.value)} + placeholder="Enter your email" + className="flex-1 px-4 py-3 border border-nest-border rounded-full focus:outline-none focus:border-nest-red" + required + /> + + +
+
+ ); +}; + +export default Newsletter; \ No newline at end of file diff --git a/src/components/SupportSection.js b/src/components/SupportSection.js new file mode 100644 index 0000000..8ba0b72 --- /dev/null +++ b/src/components/SupportSection.js @@ -0,0 +1,158 @@ +import React from 'react'; +import { motion, useReducedMotion } from 'framer-motion'; + +const fadeUpPreset = (delay = 0, duration = 1.2) => ({ + initial: { opacity: 0, y: 20 }, + whileInView: { opacity: 1, y: 0 }, + viewport: { once: true, amount: 0.2 }, + transition: { delay, duration, ease: "easeOut" } +}); + +const SupportSection = () => { + const shouldReduceMotion = useReducedMotion(); + + const principalSponsors = [ + { name: "Trilon", logo: "https://nestjs.com/trilon.22c96544.svg", link: "https://trilon.io/" }, + { name: "Red Hat", logo: "https://nestjs.com/red-hat-logo.17d10010.svg", link: "https://www.redhat.com/" }, + { name: "Jetbrains", logo: "https://nestjs.com/jetbrains-logo.d24f46f1.svg", link: "https://www.jetbrains.com/" } + ]; + + const goldSponsors = [ + { name: "Movavi", logo: "https://nestjs.com/movavi-logo.eee1bd94.svg", link: "https://www.movavi.com/" }, + { name: "Handsontable", logo: "https://nestjs.com/handsontable-logo.9006297e.svg", link: "https://handsontable.com/docs/react-data-grid/?utm_source=NestJS_homepage&utm_medium=sponsorship&utm_campaign=library_sponsorship_2024" }, + { name: "Arcjet", logo: "https://nestjs.com/arcjet-logo.79e2da28.svg", link: "https://arcjet.com/?ref=nestjs" }, + { name: "Crawljobs", logo: "https://nestjs.com/crawljobs-logo.53b333f7.svg", link: "https://www.crawljobs.com/" } + ]; + + const silverSponsors = [ + { name: "Netlify", logo: "https://nestjs.com/netlify-logo.9322c2d1.svg", link: "https://www.netlify.com/" }, + { name: "SwingDev", logo: "https://nestjs.com/swingdev-logo.168e0bec.svg", link: "https://www.swingdev.io/" }, + { name: "Route4Me", logo: "https://nestjs.com/route4me-logo.d07e8982.svg", link: "https://www.route4me.com/" } + ]; + + if (shouldReduceMotion) { + return ( +
+
+

Support us

+

+ Nest is an MIT-licensed open-source project. Hence, it grows thanks to the sponsors and support by the amazing backers. Please, consider supporting us! +

+ + {/* Principal Sponsors */} +
+

PRINCIPAL SPONSORS

+
+ {principalSponsors.map((sponsor, index) => ( + + {sponsor.name} + + ))} +
+
+ + {/* Gold Sponsors */} +
+

GOLD SPONSORS

+
+ {goldSponsors.map((sponsor, index) => ( + + {sponsor.name} + + ))} +
+
+ + {/* Silver Sponsors */} +
+

SILVER SPONSORS

+
+ {silverSponsors.map((sponsor, index) => ( + + {sponsor.name} + + ))} +
+
+ + +
+
+ ); + } + + return ( +
+
+ + Support us + + + Nest is an MIT-licensed open-source project. Hence, it grows thanks to the sponsors and support by the amazing backers. Please, consider supporting us! + + + {/* Principal Sponsors */} + +

PRINCIPAL SPONSORS

+
+ {principalSponsors.map((sponsor, index) => ( + + {sponsor.name} + + ))} +
+
+ + {/* Gold Sponsors */} + +

GOLD SPONSORS

+
+ {goldSponsors.map((sponsor, index) => ( + + {sponsor.name} + + ))} +
+
+ + {/* Silver Sponsors */} + +

SILVER SPONSORS

+
+ {silverSponsors.map((sponsor, index) => ( + + {sponsor.name} + + ))} +
+
+ + + Become a sponsor / backer + +
+
+ ); +}; + +export default SupportSection; \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..ee80855 --- /dev/null +++ b/src/index.css @@ -0,0 +1,36 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html { + scroll-behavior: smooth; + } + + body { + font-family: 'Inter', system-ui, sans-serif; + line-height: 1.6; + } +} + +@layer components { + .btn-primary { + @apply bg-nest-red text-white px-8 py-3 rounded-full font-medium hover:bg-red-600 transition-colors duration-200; + } + + .btn-secondary { + @apply border-2 border-white text-white px-8 py-3 rounded-full font-medium hover:bg-white hover:text-nest-dark transition-all duration-200; + } + + .feature-card { + @apply bg-white p-8 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200; + } + + .section-padding { + @apply py-16 md:py-24; + } + + .container-custom { + @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8; + } +} \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..1ede065 --- /dev/null +++ b/src/index.js @@ -0,0 +1,8 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import './index.css'; +import App from './App'; + +const container = document.getElementById('root'); +const root = createRoot(container); +root.render(); \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..c61ba45 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,25 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./src/**/*.{js,jsx,ts,tsx}", + ], + theme: { + extend: { + colors: { + 'nest-red': '#e0234e', + 'nest-dark': '#1a1a1a', + 'nest-gray': '#666666', + 'nest-light-gray': '#f5f5f5', + 'nest-border': '#e5e5e5' + }, + fontFamily: { + 'sans': ['Inter', 'system-ui', 'sans-serif'] + }, + backgroundImage: { + 'hero-pattern': "url('https://nestjs.com/header.e5c9eff6.webp')", + 'support-pattern': "url('https://nestjs.com/support.1356a495.png')" + } + }, + }, + plugins: [], +} \ No newline at end of file diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..760984a --- /dev/null +++ b/vercel.json @@ -0,0 +1,5 @@ +{ + "installCommand": "npm install", + "buildCommand": "CI=false npm run build", + "outputDirectory": "build" +} \ No newline at end of file