Initial commit

This commit is contained in:
2026-01-14 14:37:01 +02:00
commit 55a74476bc
48 changed files with 2248 additions and 0 deletions

1
.env.production Normal file
View File

@@ -0,0 +1 @@
DISABLE_ESLINT_PLUGIN=true

View File

@@ -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"

41
package.json Normal file
View File

@@ -0,0 +1,41 @@
{
"name": "nestjs-enterprise",
"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"
]
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -0,0 +1 @@
PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDY4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMS40MTQiPjxwYXRoIGZpbGw9IiMzMzMiIGQ9Ik00OS43MzUgNTguMzVhNC44MjMgNC44MjMgMCAwIDEgNC44MzgtNC44MzggNC44MjIgNC44MjIgMCAwIDEgNC44MzcgNC44MzggNC44MjIgNC44MjIgMCAwIDEtNC44MzcgNC44MzggNC44MjMgNC44MjMgMCAwIDEtNC44MzgtNC44MzhtMTkuNjgyIDBhNC44MjMgNC44MjMgMCAwIDEgNC44MzgtNC44MzggNC44MjIgNC44MjIgMCAwIDEgNC44MzcgNC44MzggNC44MjIgNC44MjIgMCAwIDEtNC44MzcgNC44MzggNC44MjMgNC44MjMgMCAwIDEtNC44MzgtNC44MzhtLTQ1LjYyNiAwYTQuODIyIDQuODIyIDAgMCAxIDQuODM4LTQuODM4IDQuODIyIDQuODIyIDAgMCAxIDQuODM3IDQuODM4IDQuODIyIDQuODIyIDAgMCAxLTQuODM3IDQuODM4IDQuODIyIDQuODIyIDAgMCAxLTQuODM4LTQuODM4bS0xOS42ODIgMGE0LjgyMiA0LjgyMiAwIDAgMSA0LjgzNy00LjgzOCA0LjgyMiA0LjgyMiAwIDAgMSA0LjgzOCA0LjgzOCA0LjgyMiA0LjgyMiAwIDAgMS00LjgzOCA0LjgzOCA0LjgyMiA0LjgyMiAwIDAgMS00LjgzNy00LjgzOG0zOS43OTQtOC41NDloLTQuMjA4djE2LjkzMmg0LjIwOFY0OS44MDF6TTEzLjc1MSA2Ni43MzNoNC4yMDhWNDkuODAxaC00LjIwOHYxLjM1OWE4LjY5OCA4LjY5OCAwIDAgMC01LjAwMy0xLjU1N0E4LjczOSA4LjczOSAwIDAgMCAwIDU4LjM1YTguNzE4IDguNzE4IDAgMCAwIDguNzQ4IDguNzQ3IDguNjk4IDguNjk4IDAgMCAwIDUuMDAzLTEuNTU3djEuMTkzem02NS4zMDggMGg0LjIwOFY0OS44MDFoLTQuMjA4djEuMzU5YTguNjk4IDguNjk4IDAgMCAwLTUuMDAzLTEuNTU3IDguNzM4IDguNzM4IDAgMCAwLTguNzQ3IDguNzQ3IDguNzE3IDguNzE3IDAgMCAwIDguNzQ3IDguNzQ3IDguNjk4IDguNjk4IDAgMCAwIDUuMDAzLTEuNTU3djEuMTkzem01Ljc2Ni01LjUwMWMuMTMyIDMuNDEzIDMuMDQ4IDUuODMyIDcuOTE5IDUuODMyIDMuOTc2IDAgNy4yNTYtMS43MjMgNy4yNTYtNS41MzMgMC0yLjY1MS0xLjQ5MS00LjIwOC00LjkzNy00Ljg3MWwtMi42ODQtLjUzYy0xLjcyMy0uMzMxLTIuOTE2LS42NjMtMi45MTYtMS42OSAwLTEuMTI2IDEuMTYtMS42MjMgMi42MTgtMS42MjMgMi4xMjEgMCAyLjk4MiAxLjA2IDMuMDQ4IDIuMzE5aDQuMjQyYy0uMjMyLTMuMzE0LTIuODgzLTUuNTMzLTcuMTU3LTUuNTMzLTQuNDA3IDAtNy4wMjUgMi40MTgtNy4wMjUgNS41NjYgMCAzLjg0NCAzLjExNSA0LjQ3MyA1Ljc5OSA0Ljk3bDIuMjIuMzk4YzEuNTkuMjk4IDIuMjg2Ljc2MiAyLjI4NiAxLjY5IDAgLjgyOC0uNzk1IDEuNjU2LTIuNjg0IDEuNjU2LTIuNzUgMC0zLjY0NS0xLjQyNC0zLjY3OC0yLjY1MWgtNC4zMDd6TTMzLjQzMyA0NC4wMzZ2Ny4xMjRhOC42OTggOC42OTggMCAwIDAtNS4wMDMtMS41NTcgOC43MzkgOC43MzkgMCAwIDAtOC43NDggOC43NDcgOC43MTggOC43MTggMCAwIDAgOC43NDggOC43NDcgOC42OTggOC42OTggMCAwIDAgNS4wMDMtMS41NTd2MS4xOTNoNC4yMDhWNDQuMDM2aC00LjIwOHptMjUuOTQ0IDB2Ny4xMjRhOC42OTggOC42OTggMCAwIDAtNS4wMDMtMS41NTcgOC43MzggOC43MzggMCAwIDAtOC43NDcgOC43NDcgOC43MTcgOC43MTcgMCAwIDAgOC43NDcgOC43NDcgOC42OTggOC42OTggMCAwIDAgNS4wMDMtMS41NTd2MS4xOTNoNC4yMDhWNDQuMDM2aC00LjIwOHptLTQ4LjQ0My01LjAwM2wyLjg1IDUuMDAzaDE5LjY0OWwtNy43ODctMTMuNDUzLTE0LjcxMiA4LjQ1em0zMi45NjkgOS4yMTF2LTQuMjA4aDE1LjQ3NEw0Mi44NzYgMTUuNDc0bC0xNC43NDUgOC40NDkgMTEuNTY0IDIwLjExM3Y0LjIwOGg0LjIwOHptMjEuNzM3LTQuMjA4aDE5LjY4Mkw1OS44NzQgMCA0NS4xNjMgOC40ODIgNjUuNjQgNDQuMDM2eiIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABLFBMVEUAAADgI07hI07gJU3gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07///8RYHHZAAAAYnRSTlMAAAAACEkrDQEDBorPkwoZa6CunnGy9UW+/v36XR4EMYnY2US0O5TXeqUHx+706Ok2M18wPoPk/G5B3otmghqiNQle3/FULpac8tuXrdVYqPnwjCJSTh1I07OdtoY0KRQ4ApuOtd0AAAABYktHRGNcvi2qAAAAB3RJTUUH5QIECQU6y1Xy3gAAANBJREFUGNNjYIAARhZWNnZGJgiHmZGDk4OLm4eXjxEsx8gvICgkLCKaJCbOCOazSUgmJSVJSSdJycjKMTLIKygmQYGSsooqI4MajCuprqGZpKnFwKYtraML0iOppy+ZpGfAwGhoZGxiagZVZm4BNJSDkZHR0goqYg22h0WO0cYcImALErCzd3B00ncGCkm5uIIE3PTcPTy9vKWSkpw97EACfD5J5r5+/kkBgUGyHGAzgkNCw8IjpCKjghkZYZ7lZI2OiY2D85kY410T5BI5gHwAqtoq4cCuYkgAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjEtMDItMDRUMDk6MDU6NTgrMDE6MDAZPq6OAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIxLTAyLTA0VDA5OjA1OjU4KzAxOjAwaGMWMgAAAFd6VFh0UmF3IHByb2ZpbGUgdHlwZSBpcHRjAAB4nOPyDAhxVigoyk/LzEnlUgADIwsuYwsTIxNLkxQDEyBEgDTDZAMjs1Qgy9jUyMTMxBzEB8uASKBKLgDqFxF08kI1lQAAAABJRU5ErkJggg==

View File

@@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACEFBMVEUAAADgI07gJ0rgI0/gIk7fJE/gJE7gHk/gIk/hIE/hI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07gI07///+TdNRjAAAArnRSTlMAAAAAAAAAAAAAAAIVBwSBkyBDDV7bf+umHm6p5KoFIURgb19CCmnj+FUBNZ3h9/723qeI8Zlh5fuxZe6ePxtF85TOH3nc9bsRLuCPAz7s/b0puTr80II8mlLt0uIm8mKAcUZAUHq8mxI3C0vCwRmg1hqsLN3XHMQPXatONGsGE5zLuvpWhDPf9LTHKMaMhpcxWlEj8KOR+QhMou+2rc2/fmevVHXaEDiFrm0iJQldRelWAAAAAWJLR0SvzmyjMQAAAAd0SU1FB+UCBAkFOstV8t4AAAH4SURBVDjLY2BAA4zcPLyMjAy4ASMfv4CgkDBuNYyMIqJi4hKSOFUwMkpJy6xbJyuMqoCJUU5eQVFJSVlFUlVNfd26dRqaKEYwamnr6Orpr1unb2BoZGwCVLDOlBlJASO3mfk6OLDQB5GWfNxaMCWMclbW69CBDaOKLdgWRj47ex0HDHkLZUZHJ2eQAl4XV7d1mMDdw9NrnbcPUIWvHxZp/4BAwaB168SDGVkYgtUxpENCw8LNnECsCKARWpFRGPplomUswKyYWEagF8Li1ulrGFhgsWmdfjzQEYy8CU6JSckpqWmYflmXrgUK/IxMoFWMjFnZOfroCnKFUaIpL98fTUFBIXKMsTJmFKEpcBVEi+riElQFpWUIOW5GkEMSUBWUV8ATWmVVNSMjI1uN+Do3pIDR0YIpyBRfV8tYV6/WILqusQkq2+ygrwiP8Rb/da18bd7t+s3rXGShCtoDXAXhCmr81nV0doGCM6e7B6pAtrcPnu4Y6/qhoqETtKMg6ap54qTJ8GTHqGUFTolTpgZyTwPLd03PrZ+hhVDAzjOzb5ZNavAMxkmzQQE+R2B2NlrW4ODU0mJk1Ep2nzsP6P/g+Qt8sGUdRrlA54WzQxZNXpygijVrcTGqLpm9NHHZjOXY5Rm1YlesXCWoxailhT1rMvqsXrMW1W0AHSM0aNKRcBcAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjEtMDItMDRUMDk6MDU6NTgrMDE6MDAZPq6OAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIxLTAyLTA0VDA5OjA1OjU4KzAxOjAwaGMWMgAAAFd6VFh0UmF3IHByb2ZpbGUgdHlwZSBpcHRjAAB4nOPyDAhxVigoyk/LzEnlUgADIwsuYwsTIxNLkxQDEyBEgDTDZAMjs1Qgy9jUyMTMxBzEB8uASKBKLgDqFxF08kI1lQAAAABJRU5ErkJggg==

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
PHN2ZyBoZWlnaHQ9IjE4MCIgdmlld0JveD0iMCAwIDE4MCAxODAiIHdpZHRoPSIxODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIzMi42NCIgeDI9IjgyLjc3IiB5MT0iNjEuMTYiIHkyPSI4NS41NCI+PHN0b3Agb2Zmc2V0PSIuMjEiIHN0b3AtY29sb3I9IiNmZTI4NTciLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMyOTM4OTYiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iYiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIxNy4zOCIgeDI9IjgyLjk1IiB5MT0iNjkuODYiIHkyPSIyMS4yMyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZmUyODU3Ii8+PHN0b3Agb2Zmc2V0PSIuMDEiIHN0b3AtY29sb3I9IiNmZTI4NTciLz48c3RvcCBvZmZzZXQ9Ii44NiIgc3RvcC1jb2xvcj0iI2ZmMzE4YyIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJjIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ijc0LjE3IiB4Mj0iMTYwLjI3IiB5MT0iMjEuNTgiIHkyPSI5OS43NiI+PHN0b3Agb2Zmc2V0PSIuMDIiIHN0b3AtY29sb3I9IiNmZjMxOGMiLz48c3RvcCBvZmZzZXQ9Ii4yMSIgc3RvcC1jb2xvcj0iI2ZlMjg1NyIvPjxzdG9wIG9mZnNldD0iLjg2IiBzdG9wLWNvbG9yPSIjZmRiNjBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMTU1LjQ2IiB4Mj0iNTUuMDciIHkxPSI4OS44IiB5Mj0iMTU4LjkiPjxzdG9wIG9mZnNldD0iLjAxIiBzdG9wLWNvbG9yPSIjZmRiNjBkIi8+PHN0b3Agb2Zmc2V0PSIuODYiIHN0b3AtY29sb3I9IiNmY2Y4NGEiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGQ9Im04MS41NiA4My43MS00MS4zNS0zNWExNSAxNSAwIDEgMCAtMTQuNDcgMjUuN2guMTVsLjM5LjEyIDUyLjE2IDE1Ljg5YTMuNTMgMy41MyAwIDAgMCAxLjE4LjIxIDMuNzMgMy43MyAwIDAgMCAxLjkzLTYuOTF6IiBmaWxsPSJ1cmwoI2EpIi8+PHBhdGggZD0ibTg5Ljg1IDI1LjkzYTEwLjg5IDEwLjg5IDAgMCAwIC0xNi44NS05LjE4bC01MC41IDMwLjY2YTE1IDE1IDAgMSAwIDE3LjkgMjRsNDUuMjctMzYuODkuMzYtLjNhMTAuOTMgMTAuOTMgMCAwIDAgMy44Mi04LjI5eiIgZmlsbD0idXJsKCNiKSIvPjxwYXRoIGQ9Im0xNjMuMjkgOTItNzYuNjItNzMuNzlhMTAuOTEgMTAuOTEgMCAxIDAgLTE0LjgxIDE2bC4xNC4xMiA4MS40IDY4LjU4YTcuMzYgNy4zNiAwIDAgMCAxMi4wOS01LjY1IDcuMzkgNy4zOSAwIDAgMCAtMi4yLTUuMjZ6IiBmaWxsPSJ1cmwoI2MpIi8+PHBhdGggZD0ibTE2NS41IDk3LjI5YTcuMzUgNy4zNSAwIDAgMCAtMTEuNjctNmwtOTIuNzEgNDUuM2ExNSAxNSAwIDEgMCAxNS40OCAyNS41OWw4NS43My01OC44NGE3LjM1IDcuMzUgMCAwIDAgMy4xNy02LjA1eiIgZmlsbD0idXJsKCNkKSIvPjxwYXRoIGQ9Im02MCA2MGg2MHY2MGgtNjB6Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTY2LjUzIDEwOC43NWgyMi41djMuNzVoLTIyLjV6Ii8+PHBhdGggZD0ibTY1LjU5IDc1LjQ3IDEuNjctMS41OGExLjg4IDEuODggMCAwIDAgMS40Ny44N2MuNjQgMCAxLjA2LS40NSAxLjA2LTEuMzJ2LTUuOTJoMi41OHY1Ljk0YTMuNDQgMy40NCAwIDAgMSAtLjkyIDIuNjMgMy41MiAzLjUyIDAgMCAxIC0yLjU3IDEgMy44NCAzLjg0IDAgMCAxIC0zLjI5LTEuNjJ6Ii8+PHBhdGggZD0ibTczLjUzIDY3LjUyaDcuNTN2Mi4xOWgtNXYxLjQzaDQuNDl2MmgtNC40NXYxLjQ5aDV2Mi4yaC03LjZ6Ii8+PHBhdGggZD0ibTg0LjczIDY5Ljc5aC0yLjh2LTIuMjdoOC4yMXYyLjI3aC0yLjgxdjcuMDloLTIuNnoiLz48cGF0aCBkPSJtNjYuNjMgODAuNThoNC40MmEzLjQ3IDMuNDcgMCAwIDEgMi41NS44MyAyLjA5IDIuMDkgMCAwIDEgLjYxIDEuNTIgMi4xOCAyLjE4IDAgMCAxIC0xLjQ1IDIuMDkgMi4yNyAyLjI3IDAgMCAxIDEuODYgMi4yOWMwIDEuNjktMS4zMSAyLjY5LTMuNTUgMi42OWgtNC40NHptNSAyLjg5YzAtLjUyLS40Mi0uOC0xLjE4LS44aC0xLjI5djEuNjRoMS4yNWMuNzggMCAxLjI0LS4yNyAxLjI0LS44MXptLS45IDIuNjZoLTEuNTd2MS43M2gxLjYyYy44IDAgMS4yNC0uMzEgMS4yNC0uODYtLjAyLS41My0uNC0uODctMS4yNy0uODd6Ii8+PHBhdGggZD0ibTc1LjQ1IDgwLjU4aDQuMTVhNC4xNCA0LjE0IDAgMCAxIDMuMDUgMSAyLjkyIDIuOTIgMCAwIDEgLjgzIDIuMTggMyAzIDAgMCAxIC0xLjkzIDIuODlsMi4yNCAzLjM1aC0zbC0xLjg5LTIuODRoLS44N3YyLjg0aC0yLjZ6bTQgNC41Yy44NyAwIDEuNC0uNDMgMS40LTEuMTIgMC0uNzUtLjU1LTEuMTMtMS40MS0xLjEzaC0xLjM5djIuMjd6Ii8+PHBhdGggZD0ibTg3LjA5IDgwLjUxaDIuNWw0IDkuNDRoLTIuNzlsLS42Ny0xLjY5aC0zLjYzbC0uNjcgMS43NGgtMi43MXptMi4yOCA1LjczLTEuMDUtMi42NS0xLjA2IDIuNjV6Ii8+PHBhdGggZD0ibTk0IDgwLjU1aDIuNnY5LjM3aC0yLjZ6Ii8+PHBhdGggZD0ibTk3LjU2IDgwLjU1aDIuNDRsMy4zNyA1di01aDIuNTd2OS4zN2gtMi4yN2wtMy41My01LjE0djUuMTRoLTIuNTh6Ii8+PHBhdGggZD0ibTEwNi4zNyA4OC41MyAxLjQ0LTEuNzNhNC44NiA0Ljg2IDAgMCAwIDMgMS4xM2MuNzEgMCAxLjA4LS4yNSAxLjA4LS42NSAwLS40MS0uMy0uNjEtMS41OS0uOTEtMi0uNDYtMy41My0xLTMuNTMtMi45MyAwLTEuNzQgMS4zOC0zIDMuNjMtM2E1Ljg4IDUuODggMCAwIDEgMy44NSAxLjI1bC0xLjI1IDEuNzhhNC41NiA0LjU2IDAgMCAwIC0yLjYyLS45MmMtLjYzIDAtLjk0LjI1LS45NC42IDAgLjQzLjMyLjYyIDEuNjMuOTEgMi4xNS40NyAzLjQ4IDEuMTcgMy40OCAyLjkyIDAgMS45MS0xLjUxIDMtMy43OCAzYTYuNTYgNi41NiAwIDAgMSAtNC40LTEuNDV6Ii8+PC9nPjxwYXRoIGQ9Im0wIDBoMTgwdjE4MGgtMTgweiIgZmlsbD0ibm9uZSIvPjwvc3ZnPg==

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
PHN2ZyBpZD0iYjZiZGQyYjQtNTJhYi00ODhhLTlhMzAtMWU2ZDFkN2RkMmQ0IiBkYXRhLW5hbWU9IkxheWVyIDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDYxMS44IDE0NCI+PGRlZnM+PHN0eWxlPi5hNzM3NDU5Yy1lOGM3LTRhZmEtODAwOC1mNmNmZDE1Y2NkYTJ7ZmlsbDojZTAwO308L3N0eWxlPjwvZGVmcz48cGF0aCBkPSJNNTc5LjMsOTIuM2MwLDExLjksNy4yLDE3LjcsMjAuMiwxNy43YTUzLjM5LDUzLjM5LDAsMCwwLDExLjktMS43Vjk0LjVhMjUuMjcsMjUuMjcsMCwwLDEtNy43LDEuMmMtNS40LDAtNy40LTEuNy03LjQtNi43VjY3LjhoMTUuNlY1My42SDU5Ni4zdi0xOGwtMTcsMy43VjUzLjZINTY4VjY3LjhoMTEuMmwuMSwyNC41Wm0tNTMsLjNjMC0zLjcsMy43LTUuNSw5LjMtNS41YTM4LjM1LDM4LjM1LDAsMCwxLDEwLjEsMS4zdjcuMmEyMC44MiwyMC44MiwwLDAsMS0xMC42LDIuNmMtNS41LDAtOC44LTIuMS04LjgtNS42bTUuMiwxNy42YTI2LjY5LDI2LjY5LDAsMCwwLDE1LjQtNC4zdjMuNGgxNi44VjczLjZjMC0xMy42LTkuMS0yMS0yNC40LTIxLTguNSwwLTE2LjksMi0yNiw2LjFsNi4xLDEyLjVjNi41LTIuNywxMi00LjQsMTYuOC00LjQsNywwLDEwLjYsMi43LDEwLjYsOC4zdjIuN2E0OC45Miw0OC45MiwwLDAsMC0xMi42LTEuNmMtMTQuMywwLTIyLjksNi0yMi45LDE2LjcsMCw5LjgsNy44LDE3LjMsMjAuMiwxNy4zbS05Mi40LS45aDE4LjFWODAuNGgzMC4zdjI4LjhoMTguMVYzNS42SDQ4Ny41VjYzLjlINDU3LjJWMzUuNkg0MzkuMVpNMzcwLjIsODEuNGMwLTgsNi4zLTE0LjEsMTQuNi0xNC4xYTE3LjcyLDE3LjcyLDAsMCwxLDExLjgsNC4zVjkxLjFhMTYuNjIsMTYuNjIsMCwwLDEtMTEuOCw0LjVjLTguMi0uMS0xNC42LTYuMi0xNC42LTE0LjJtMjYuNiwyNy45aDE2LjhWMzEuOWwtMTcsMy43VjU2LjVhMjguMTQsMjguMTQsMCwwLDAtMTQuMi0zLjdjLTE2LjIsMC0yOC45LDEyLjUtMjguOSwyOC41YTI4LjI1LDI4LjI1LDAsMCwwLDI3LjksMjguNmguNWEyNS40NiwyNS40NiwwLDAsMCwxNC45LTQuOFpNMzE5LjYsNjYuNWM1LjQsMCw5LjksMy41LDExLjcsOC44SDMwOC4xYTExLjU2LDExLjU2LDAsMCwxLDExLjUtOC44bS0yOC43LDE1YzAsMTYuMiwxMy4yLDI4LjgsMzAuMywyOC44LDkuNCwwLDE2LjItMi41LDIzLjItOC40bC0xMS4zLTEwYy0yLjYsMi43LTYuNSw0LjItMTEuMSw0LjJhMTQuMzcsMTQuMzcsMCwwLDEtMTMuNy04LjhoMzkuNlY4My4xYzAtMTcuNy0xMS45LTMwLjQtMjguMS0zMC40YTI4LjU4LDI4LjU4LDAsMCwwLTI5LDI4LjEsMS40OCwxLjQ4LDAsMCwxLC4xLjdNMjYxLjYsNTEuMWM2LDAsOS40LDMuOCw5LjQsOC4zcy0zLjQsOC4zLTkuNCw4LjNIMjQzLjdWNTEuMVptLTM2LDU4LjFoMTguMVY4Mi40aDEzLjhsMTMuOSwyNi44aDIwLjJMMjc1LjQsNzkuN0EyMi4zMiwyMi4zMiwwLDAsMCwyODkuMyw1OWMwLTEzLjItMTAuNC0yMy41LTI2LTIzLjVIMjI1LjZ2NzMuN1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjEpIi8+PHBhdGggY2xhc3M9ImE3Mzc0NTljLWU4YzctNGFmYS04MDA4LWY2Y2ZkMTVjY2RhMiIgZD0iTTEyNy4xLDgzYzEyLjUsMCwzMC42LTIuNiwzMC42LTE3LjVhMTkuNTMsMTkuNTMsMCwwLDAtLjMtMy40TDE1MCwyOS43Yy0xLjctNy4xLTMuMi0xMC40LTE1LjctMTYuNkMxMjQuNiw4LjEsMTAzLjUsMCw5Ny4yLDBjLTUuOSwwLTcuNiw3LjUtMTQuNSw3LjVDNzYsNy41LDcxLjEsMS45LDY0LjgsMS45Yy02LDAtOS45LDQuMS0xMi45LDEyLjUsMCwwLTguNCwyMy43LTkuNSwyNy4yYTYuMTUsNi4xNSwwLDAsMC0uMiwxLjljLS4xLDkuMiwzNi4yLDM5LjQsODQuOSwzOS41bTMyLjUtMTEuNGMxLjcsOC4yLDEuNyw5LjEsMS43LDEwLjEsMCwxNC0xNS43LDIxLjgtMzYuNCwyMS44LTQ2LjgsMC04Ny43LTI3LjQtODcuNy00NS41YTE4LjM1LDE4LjM1LDAsMCwxLDEuNS03LjNDMjEuOSw1MS41LjEsNTQuNS4xLDczLjcuMSwxMDUuMiw3NC43LDE0NCwxMzMuNywxNDRjNDUuMywwLDU2LjctMjAuNSw1Ni43LTM2LjcsMC0xMi43LTExLTI3LjEtMzAuOC0zNS43IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC4xKSIvPjxwYXRoIGQ9Ik0xNTkuNiw3MS42YzEuNyw4LjIsMS43LDkuMSwxLjcsMTAuMSwwLDE0LTE1LjcsMjEuOC0zNi40LDIxLjgtNDYuOCwwLTg3LjctMjcuNC04Ny43LTQ1LjVhMTguMzUsMTguMzUsMCwwLDEsMS41LTcuM2wzLjctOS4xYTYuMTUsNi4xNSwwLDAsMC0uMiwxLjljMCw5LjIsMzYuMywzOS40LDg0LjksMzkuNCwxMi41LDAsMzAuNi0yLjYsMzAuNi0xNy41YTE5LjUzLDE5LjUzLDAsMCwwLS4zLTMuNFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjEpIi8+PC9zdmc+

View File

@@ -0,0 +1 @@
PHN2ZyBpZD0iX2RldmVsb3BtZW50LS1hc3NldHMtLWltZy0tX3N2Zy1zcHJpdGVzLS1yZXdlLWRpZ2l0YWwiIHZpZXdCb3g9IjAgMCAyMTAgMzcuNjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSI+PHBhdGggY2xhc3M9ImJtc3QwIiBkPSJNMTMuOTcgMjkuMzFsLTMuMDctOC4xMmMtMS4xNC0zLjAyLTEuNzgtMy40Mi0zLjQyLTMuNDJ2MTEuNTRIMFYuMTloMTAuMDFjOC41NyAwIDExLjM0IDMuNDcgMTEuMzQgOC4zMiAwIDUtMi42MyA3LjU3LTYuMDQgOC4xMi45OS4zIDIuMTggMS42MyAyLjkyIDMuMTcuOTQgMS45MyAzLjQxIDcuMzMgNC4zNSA5LjUxaC04LjYxek03LjQ4IDYuMzR2NS45NGgyLjEzYzIuNTIgMCAzLjQxLTEuMjQgMy40MS0zLjE3IDAtMi4wOC0xLjE0LTIuNzctMy40Ny0yLjc3SDcuNDh6TTI1LjcxIDI5LjMxVi4xOWgxNi4zNHY2LjE1aC04Ljg3djQuOWg3LjI0djUuOTNoLTcuMjR2NS45aDkuOTZ2Ni4yNHpNNzMuMzEgMjkuMzFoLTcuOTdsLTEuNDktOC40MmMtLjY0LTMuNTItMS4yOS03LjMzLTEuNDMtOS4xNmgtLjA1Yy0uMDYgMS40My0uNyA1LjM0LTEuMzkgOS4xNmwtMS41NCA4LjQyaC04LjE3TDQ0LjE4LjE5aDcuOTJsMS42MyA3Ljg3YzEuMzkgNi41NCAxLjY0IDkuMzYgMS42OSAxMC40NS4yLTIuMzMuNjktNS45NCAxLjQ4LTEwLjI1TDU4LjM5LjE5aDguMzJsMS44OSA5Ljc2Yy40NCAyLjE4Ljk5IDUgMS4xOSA4LjU2aC4wNWMuMTUtMi42MyAxLjA0LTguMjYgMS41OC0xMS4wOUw3Mi45MS4xOWg3Ljk3bC03LjU3IDI5LjEyek04Mi45NiAyOS4zMVYuMTloMTYuMzl2Ni4xNWgtOC45MXY0LjloNy4yOHY1LjkzaC03LjI4djUuOWgxMHY2LjI0eiI+PC9wYXRoPjxwYXRoIGNsYXNzPSJibXN0MSIgZD0iTTIwNy4yMy4xOUgyMTBWMjkuM2gtMi43N3pNMTkyLjk3IDI2LjkzYy00LjgxIDAtOC43Mi0zLjkxLTguNzItOC43MSAwLTQuOCAzLjkxLTguNzEgOC43Mi04LjcxIDQuOCAwIDguNzEgMy45MSA4LjcxIDguNzEgMCA0LjgtMy45MSA4LjcxLTguNzEgOC43MXptMC0yMC4yYy02LjM0IDAtMTEuNDkgNS4xNS0xMS40OSAxMS40OXM1LjE1IDExLjQ5IDExLjQ5IDExLjQ5YzMuNDYgMCA2LjU5LTEuNTMgOC43MS00LjAxdjMuNjFoMi43N1YxOC4yMmMwLTYuMzQtNS4xNS0xMS40OS0xMS40OC0xMS40OXoiPjwvcGF0aD48cGF0aCBjbGFzcz0iYm1zdDEiIGQ9Ik0xNjYuMDIgNy4xM3YyMi4xOGgyLjc3VjkuOWg1Ljk1djE5LjQxaDIuNzdWOS45aDUuN1Y3LjEzaC01LjdWLjE5aC0yLjc3djYuOTR6TTE1MS43NSA5LjVjLTQuOCAwLTguNzIgMy45MS04LjcyIDguNzEgMCA0LjggMy45MSA4LjcxIDguNzIgOC43MSA0LjgxIDAgOC43Mi0zLjkxIDguNzItOC43MSAwLTQuOC0zLjkxLTguNzEtOC43Mi04Ljcxem0xMS40OSAxNi42NGMwIDYuMzQtNS4xNSAxMS40OS0xMS40OSAxMS40OS01LjU5IDAtMTAuMjUtNC4wMS0xMS4yOS05LjMxaDIuODhjLjk0IDMuNzYgNC4zNiA2LjU0IDguNDIgNi41NCA0LjgxIDAgOC43Mi0zLjkxIDguNzItOC43MXYtLjQ0Yy0yLjEzIDIuNDctNS4yNSA0LjAxLTguNzIgNC4wMS02LjM0IDAtMTEuNDktNS4xNS0xMS40OS0xMS40OXM1LjE1LTExLjQ5IDExLjQ5LTExLjQ5IDExLjQ5IDUuMTUgMTEuNDkgMTEuNDl2Ny45MXpNMTM1LjAyIDcuMTNoMi43N3YyMi4xOGgtMi43N3pNMTIwLjU1IDkuNWMtNC44IDAtOC43MSAzLjkxLTguNzEgOC43MSAwIDQuOCAzLjkxIDguNzEgOC43MSA4LjcxIDQuOCAwIDguNzEtMy45MSA4LjcxLTguNzEuMDEtNC44LTMuOTEtOC43MS04LjcxLTguNzF6bTExLjQ5IDguNzJjMCA2LjM0LTUuMTUgMTEuNDktMTEuNDkgMTEuNDlzLTExLjQ5LTUuMTUtMTEuNDktMTEuNDkgNS4xNS0xMS40OSAxMS40OS0xMS40OWMzLjQ3IDAgNi41OCAxLjUzIDguNzEgNC4wMVYuMTloMi43OHYxOC4wM3pNMTM2LjQgMGMuODkgMCAxLjU4LjY5IDEuNTggMS41OCAwIC44OS0uNyAxLjU4LTEuNTggMS41OC0uOSAwLTEuNTktLjY5LTEuNTktMS41OCAwLS44OS43LTEuNTggMS41OS0xLjU4ek0xNjcuNCAwYy44OSAwIDEuNTkuNjkgMS41OSAxLjU4IDAgLjg5LS43IDEuNTgtMS41OSAxLjU4LS44OSAwLTEuNTgtLjY5LTEuNTgtMS41OCAwLS44OS42OS0xLjU4IDEuNTgtMS41OHoiPjwvcGF0aD48L3N2Zz4=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1232
public/index.html Normal file

File diff suppressed because it is too large Load Diff

28
src/App.js Normal file
View File

@@ -0,0 +1,28 @@
import React from 'react';
import Header from './components/Header';
import Hero from './components/Hero';
import AccelerateSection from './components/AccelerateSection';
import TeamAugmentation from './components/TeamAugmentation';
import CompanyLogos from './components/CompanyLogos';
import Services from './components/Services';
import CTA from './components/CTA';
import Newsletter from './components/Newsletter';
import Footer from './components/Footer';
function App() {
return (
<div className="App">
<Header />
<Hero />
<AccelerateSection />
<TeamAugmentation />
<CompanyLogos />
<Services />
<CTA />
<Newsletter />
<Footer />
</div>
);
}
export default App;

View File

@@ -0,0 +1,98 @@
import React from 'react';
import { motion, useReducedMotion } from 'framer-motion';
import { CheckCircle } 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" }
});
function AccelerateSection() {
const shouldReduce = useReducedMotion();
const features = [
"Providing technical guidance & architectural reviews",
"Mentoring team members",
"Advising best practices",
"Addressing security & performance concerns",
"Performing in-depth code reviews",
"Long-term support (LTS) & upgrade assistance"
];
if (shouldReduce) {
return (
<section className="section-padding bg-gray-50">
<div className="container-custom">
<div className="grid lg:grid-cols-2 gap-12 items-center">
<div>
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
Accelerate your development
</h2>
<p className="text-lg text-gray-600 mb-6">
We work alongside you to meet your deadlines while avoiding costly tech debt. Challenging issue? We've got you covered.
</p>
<p className="text-lg text-gray-600 mb-8">
Our goal is to help you get to market faster. Nest core team members will help you utilize best practices and choose the right strategy for unique goals.
</p>
<button className="text-brand-red font-medium hover:underline">
Contact us to learn more
</button>
</div>
<div className="space-y-4">
{features.map((feature, index) => (
<div key={index} className="flex items-start space-x-3">
<CheckCircle className="w-5 h-5 text-green-500 mt-1 flex-shrink-0" />
<span className="text-gray-700">{feature}</span>
</div>
))}
</div>
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="section-padding bg-gray-50"
>
<div className="container-custom">
<div className="grid lg:grid-cols-2 gap-12 items-center">
<motion.div {...fadeUpPreset(0.2, 1.0)}>
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
Accelerate your development
</h2>
<p className="text-lg text-gray-600 mb-6">
We work alongside you to meet your deadlines while avoiding costly tech debt. Challenging issue? We've got you covered.
</p>
<p className="text-lg text-gray-600 mb-8">
Our goal is to help you get to market faster. Nest core team members will help you utilize best practices and choose the right strategy for unique goals.
</p>
<button className="text-brand-red font-medium hover:underline">
Contact us to learn more
</button>
</motion.div>
<motion.div {...fadeUpPreset(0.3, 1.0)} className="space-y-4">
{features.map((feature, index) => (
<motion.div
key={index}
{...fadeUpPreset(0.4 + index * 0.05, 0.6)}
className="flex items-start space-x-3"
>
<CheckCircle className="w-5 h-5 text-green-500 mt-1 flex-shrink-0" />
<span className="text-gray-700">{feature}</span>
</motion.div>
))}
</motion.div>
</div>
</div>
</motion.section>
);
}
export default AccelerateSection;

61
src/components/CTA.js Normal file
View File

@@ -0,0 +1,61 @@
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" }
});
function CTA() {
const shouldReduce = useReducedMotion();
if (shouldReduce) {
return (
<section className="section-padding bg-black">
<div className="container-custom text-center">
<h2 className="text-4xl md:text-5xl font-bold text-white mb-6">
Explore enterprise services today.
</h2>
<p className="text-xl text-gray-300 mb-8">
Let's achieve your most ambitious goals - together.
</p>
<button className="btn-primary">
Contact us
</button>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="section-padding bg-black"
>
<div className="container-custom text-center">
<motion.h2
{...fadeUpPreset(0.2, 1.0)}
className="text-4xl md:text-5xl font-bold text-white mb-6"
>
Explore enterprise services today.
</motion.h2>
<motion.p
{...fadeUpPreset(0.3, 1.0)}
className="text-xl text-gray-300 mb-8"
>
Let's achieve your most ambitious goals - together.
</motion.p>
<motion.button
{...fadeUpPreset(0.4, 1.0)}
className="btn-primary"
>
Contact us
</motion.button>
</div>
</motion.section>
);
}
export default CTA;

View File

@@ -0,0 +1,102 @@
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" }
});
function CompanyLogos() {
const shouldReduce = useReducedMotion();
const companies = [
{ name: 'Sanofi', logo: 'https://enterprise.nestjs.com/assets/logos/sanofi.svg' },
{ name: 'Adidas', logo: 'https://enterprise.nestjs.com/assets/logos/adidas.svg' },
{ name: 'Autodesk', logo: 'https://enterprise.nestjs.com/assets/logos/autodesk.svg' },
{ name: 'Mercedes-Benz', logo: 'https://enterprise.nestjs.com/assets/logos/mercedes.svg' },
{ name: 'GitLab', logo: 'https://enterprise.nestjs.com/assets/logos/gitlab.svg' },
{ name: 'Red Hat', logo: 'https://enterprise.nestjs.com/assets/logos/redhat.svg' },
{ name: 'Roche', logo: 'https://enterprise.nestjs.com/assets/logos/roche.svg' },
{ name: 'IBM', logo: 'https://enterprise.nestjs.com/assets/logos/ibm.svg' },
{ name: 'Decathlon', logo: 'https://enterprise.nestjs.com/assets/logos/decathlon.svg' },
{ name: 'Societe Generale', logo: 'https://enterprise.nestjs.com/assets/logos/sg.svg' },
{ name: 'Capgemini', logo: 'https://enterprise.nestjs.com/assets/logos/capgemini.svg' },
{ name: 'REWE', logo: 'https://enterprise.nestjs.com/assets/logos/rewe.svg' }
];
if (shouldReduce) {
return (
<section className="section-padding bg-white">
<div className="container-custom text-center">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
Who is using Nest?
</h2>
<p className="text-lg text-gray-600 mb-12">
Nest is proudly powering a large ecosystem of enterprises and products out there.
<br />
Wanna see your logo here? <span className="text-brand-red font-medium">Find out more</span>.
</p>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-8 items-center">
{companies.map((company, index) => (
<div key={index} className="flex items-center justify-center h-16">
<img
src={company.logo}
alt={company.name}
className="max-h-12 max-w-full opacity-60 hover:opacity-100 transition-opacity grayscale hover:grayscale-0"
/>
</div>
))}
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="section-padding bg-white"
>
<div className="container-custom text-center">
<motion.h2
{...fadeUpPreset(0.2, 1.0)}
className="text-3xl md:text-4xl font-bold text-gray-900 mb-4"
>
Who is using Nest?
</motion.h2>
<motion.p
{...fadeUpPreset(0.3, 1.0)}
className="text-lg text-gray-600 mb-12"
>
Nest is proudly powering a large ecosystem of enterprises and products out there.
<br />
Wanna see your logo here? <span className="text-brand-red font-medium">Find out more</span>.
</motion.p>
<motion.div
{...fadeUpPreset(0.4, 1.0)}
className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-8 items-center"
>
{companies.map((company, index) => (
<motion.div
key={index}
{...fadeUpPreset(0.5 + index * 0.05, 0.6)}
className="flex items-center justify-center h-16"
>
<img
src={company.logo}
alt={company.name}
className="max-h-12 max-w-full opacity-60 hover:opacity-100 transition-opacity grayscale hover:grayscale-0"
/>
</motion.div>
))}
</motion.div>
</div>
</motion.section>
);
}
export default CompanyLogos;

44
src/components/Footer.js Normal file
View File

@@ -0,0 +1,44 @@
import React from 'react';
import { Github, X } from 'lucide-react';
function Footer() {
return (
<footer className="bg-white py-12">
<div className="container-custom">
<div className="text-center space-y-4">
<div className="flex items-center justify-center space-x-6">
<a href="#" className="text-gray-400 hover:text-gray-600 transition-colors">
<Github className="w-5 h-5" />
</a>
<a href="#" className="text-gray-400 hover:text-gray-600 transition-colors">
<X className="w-5 h-5" />
</a>
</div>
<div className="text-sm text-gray-600 space-y-2">
<p>
Official NestJS Consulting{' '}
<a href="#" className="text-brand-red hover:underline">
Trilon.io
</a>
</p>
<p>
Copyright © 2017-2026{' '}
<a href="#" className="text-brand-red hover:underline">
Kamil Mysliwiec
</a>
</p>
<p>
Designed by{' '}
<a href="#" className="text-brand-red hover:underline">
Jakub Staron
</a>
</p>
</div>
</div>
</div>
</footer>
);
}
export default Footer;

71
src/components/Header.js Normal file
View File

@@ -0,0 +1,71 @@
import React, { useState } from 'react';
import { Menu, X, ChevronDown, Github } from 'lucide-react';
function Header() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
return (
<header className="fixed top-0 left-0 right-0 z-50 bg-black/90 backdrop-blur-sm">
<div className="container-custom">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<div className="flex items-center">
<div className="w-10 h-10 bg-brand-red rounded-lg flex items-center justify-center">
<svg viewBox="0 0 24 24" className="w-6 h-6 text-white fill-current">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>
</div>
</div>
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center space-x-8">
<a href="#" className="text-white hover:text-brand-red transition-colors">OUR WEBSITE</a>
<a href="#" className="text-white hover:text-brand-red transition-colors">COURSES</a>
<div className="relative group">
<button className="flex items-center text-white hover:text-brand-red transition-colors">
<span className="bg-brand-red text-white text-xs px-2 py-1 rounded mr-2">NEW</span>
RESOURCES
<ChevronDown className="w-4 h-4 ml-1" />
</button>
</div>
<a href="#" className="text-white hover:text-brand-red transition-colors">
<Github className="w-5 h-5" />
</a>
<a href="#" className="text-white hover:text-brand-red transition-colors">
<X className="w-5 h-5" />
</a>
</nav>
{/* Mobile menu button */}
<button
className="md:hidden text-white"
onClick={() => setIsMenuOpen(!isMenuOpen)}
>
{isMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
</button>
</div>
{/* Mobile Navigation */}
{isMenuOpen && (
<div className="md:hidden bg-black/95 absolute top-16 left-0 right-0 border-t border-gray-800">
<nav className="flex flex-col space-y-4 p-4">
<a href="#" className="text-white hover:text-brand-red transition-colors">OUR WEBSITE</a>
<a href="#" className="text-white hover:text-brand-red transition-colors">COURSES</a>
<a href="#" className="text-white hover:text-brand-red transition-colors">RESOURCES</a>
<div className="flex space-x-4 pt-2">
<a href="#" className="text-white hover:text-brand-red transition-colors">
<Github className="w-5 h-5" />
</a>
<a href="#" className="text-white hover:text-brand-red transition-colors">
<X className="w-5 h-5" />
</a>
</div>
</nav>
</div>
)}
</div>
</header>
);
}
export default Header;

93
src/components/Hero.js Normal file
View File

@@ -0,0 +1,93 @@
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" }
});
function Hero() {
const shouldReduce = useReducedMotion();
if (shouldReduce) {
return (
<section className="relative min-h-screen bg-black flex items-center overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-black via-black/80 to-transparent z-10"></div>
<div className="absolute inset-0">
<img
src="https://enterprise.nestjs.com/assets/hero-bg.jpg"
alt="Cat background"
className="w-full h-full object-cover opacity-60"
/>
</div>
<div className="relative z-20 container-custom">
<div className="max-w-2xl">
<h1 className="text-5xl md:text-7xl font-bold text-white mb-6">
Official support
</h1>
<p className="text-xl md:text-2xl text-gray-300 mb-8 leading-relaxed">
Our Experts become your development partner to eliminate project risk, tackling the most ambitious projects - right by your side.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button className="btn-primary">
Get in touch
</button>
<button className="btn-secondary">
Read more
</button>
</div>
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 0.8)}
className="relative min-h-screen bg-black flex items-center overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-black via-black/80 to-transparent z-10"></div>
<div className="absolute inset-0">
<img
src="https://enterprise.nestjs.com/assets/hero-bg.jpg"
alt="Cat background"
className="w-full h-full object-cover opacity-60"
/>
</div>
<div className="relative z-20 container-custom">
<div className="max-w-2xl">
<motion.h1
{...fadeUpPreset(0.2, 0.8)}
className="text-5xl md:text-7xl font-bold text-white mb-6"
>
Official support
</motion.h1>
<motion.p
{...fadeUpPreset(0.3, 0.8)}
className="text-xl md:text-2xl text-gray-300 mb-8 leading-relaxed"
>
Our Experts become your development partner to eliminate project risk, tackling the most ambitious projects - right by your side.
</motion.p>
<motion.div
{...fadeUpPreset(0.4, 0.8)}
className="flex flex-col sm:flex-row gap-4"
>
<button className="btn-primary">
Get in touch
</button>
<button className="btn-secondary">
Read more
</button>
</motion.div>
</div>
</div>
</motion.section>
);
}
export default Hero;

View File

@@ -0,0 +1,104 @@
import React, { useState } from 'react';
import { motion, useReducedMotion } from 'framer-motion';
import { ArrowRight } 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" }
});
function Newsletter() {
const [email, setEmail] = useState('');
const shouldReduce = useReducedMotion();
const handleSubmit = (e) => {
e.preventDefault();
console.log('Newsletter signup:', email);
setEmail('');
};
if (shouldReduce) {
return (
<section className="section-padding bg-gray-50">
<div className="container-custom">
<div className="max-w-2xl mx-auto text-center">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
Join our Newsletter
</h2>
<p className="text-lg text-gray-600 mb-8">
Subscribe to stay up to date with the latest Nest updates, features, and videos!
</p>
<form onSubmit={handleSubmit} className="flex flex-col sm:flex-row gap-4 max-w-md mx-auto">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-red focus:border-transparent"
required
/>
<button
type="submit"
className="bg-brand-red text-white px-6 py-3 rounded-lg font-medium hover:bg-brand-red-dark transition-colors flex items-center justify-center gap-2"
>
Subscribe
<ArrowRight className="w-4 h-4" />
</button>
</form>
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="section-padding bg-gray-50"
>
<div className="container-custom">
<div className="max-w-2xl mx-auto text-center">
<motion.h2
{...fadeUpPreset(0.2, 1.0)}
className="text-3xl md:text-4xl font-bold text-gray-900 mb-4"
>
Join our Newsletter
</motion.h2>
<motion.p
{...fadeUpPreset(0.3, 1.0)}
className="text-lg text-gray-600 mb-8"
>
Subscribe to stay up to date with the latest Nest updates, features, and videos!
</motion.p>
<motion.form
{...fadeUpPreset(0.4, 1.0)}
onSubmit={handleSubmit}
className="flex flex-col sm:flex-row gap-4 max-w-md mx-auto"
>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-red focus:border-transparent"
required
/>
<button
type="submit"
className="bg-brand-red text-white px-6 py-3 rounded-lg font-medium hover:bg-brand-red-dark transition-colors flex items-center justify-center gap-2"
>
Subscribe
<ArrowRight className="w-4 h-4" />
</button>
</motion.form>
</div>
</div>
</motion.section>
);
}
export default Newsletter;

131
src/components/Services.js Normal file
View File

@@ -0,0 +1,131 @@
import React from 'react';
import { motion, useReducedMotion } from 'framer-motion';
import { Users, Target, Zap, Search, Shield, GraduationCap } 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" }
});
function Services() {
const shouldReduce = useReducedMotion();
const services = [
{
icon: Users,
title: "DEVELOPMENT",
description: "Achieve your goals faster with Nest experts on your team tackling challenging issues right by your side."
},
{
icon: Target,
title: "TECHNICAL GUIDANCE",
description: "Enable your team to get the most out of the technology. Ensure your solutions are secure and reliable."
},
{
icon: Zap,
title: "MIGRATION ASSISTANCE",
description: "We provide a comprehensive migration assistance, ensuring you are using the latest and greatest."
},
{
icon: Search,
title: "IN-DEPTH CODE REVIEWS",
description: "Frequent code reviews can eliminate potentially hazardous bugs and issues at an early stage while enforcing best practices."
},
{
icon: Shield,
title: "LONG-TERM SUPPORT (LTS)",
description: "Have peace of mind with Nest long-term support (LTS), priority fixes, upgrade assistance, and live troubleshooting."
},
{
icon: GraduationCap,
title: "TEAM TRAININGS",
description: "Level-up your team by having expert-led Nest trainings or workshops. Get everyone up-to-speed quickly."
}
];
if (shouldReduce) {
return (
<section className="section-padding bg-gray-50">
<div className="container-custom">
<div className="text-center mb-16">
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
How can we help you be successful?
</h2>
<p className="text-lg text-gray-600 max-w-3xl mx-auto">
Nest Enterprise Consulting includes a broad range of services to empower your team.
We help you grow your business even long after our commitment is done.
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{services.map((service, index) => {
const IconComponent = service.icon;
return (
<div key={index} className="text-center p-6">
<div className="w-16 h-16 bg-brand-red rounded-full flex items-center justify-center mx-auto mb-6">
<IconComponent className="w-8 h-8 text-white" />
</div>
<h3 className="text-lg font-bold text-gray-900 mb-4">
{service.title}
</h3>
<p className="text-gray-600 leading-relaxed">
{service.description}
</p>
</div>
);
})}
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="section-padding bg-gray-50"
>
<div className="container-custom">
<motion.div
{...fadeUpPreset(0.2, 1.0)}
className="text-center mb-16"
>
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
How can we help you be successful?
</h2>
<p className="text-lg text-gray-600 max-w-3xl mx-auto">
Nest Enterprise Consulting includes a broad range of services to empower your team.
We help you grow your business even long after our commitment is done.
</p>
</motion.div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{services.map((service, index) => {
const IconComponent = service.icon;
return (
<motion.div
key={index}
{...fadeUpPreset(0.3 + index * 0.1, 0.8)}
className="text-center p-6"
>
<div className="w-16 h-16 bg-brand-red rounded-full flex items-center justify-center mx-auto mb-6">
<IconComponent className="w-8 h-8 text-white" />
</div>
<h3 className="text-lg font-bold text-gray-900 mb-4">
{service.title}
</h3>
<p className="text-gray-600 leading-relaxed">
{service.description}
</p>
</motion.div>
);
})}
</div>
</div>
</motion.section>
);
}
export default Services;

View File

@@ -0,0 +1,82 @@
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" }
});
function TeamAugmentation() {
const shouldReduce = useReducedMotion();
if (shouldReduce) {
return (
<section className="section-padding bg-brand-red">
<div className="container-custom">
<div className="grid lg:grid-cols-2 gap-12 items-center">
<div className="order-2 lg:order-1">
<img
src="https://enterprise.nestjs.com/assets/cat-chair.jpg"
alt="Cat in chair"
className="w-full max-w-md mx-auto"
/>
</div>
<div className="order-1 lg:order-2">
<h2 className="text-4xl md:text-5xl font-bold text-white mb-6">
Team augmentation. By your side at every step
</h2>
<p className="text-xl text-white/90 mb-8 leading-relaxed">
Nest core team members can work directly with your team on a daily basis to help take your project to the next-level. Let us partner with you and your team to develop the most ambitious projects.
</p>
<button className="bg-white text-brand-red px-8 py-3 rounded-full font-medium hover:bg-gray-100 transition-colors">
Contact us to learn more
</button>
</div>
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="section-padding bg-brand-red"
>
<div className="container-custom">
<div className="grid lg:grid-cols-2 gap-12 items-center">
<motion.div
{...fadeUpPreset(0.2, 1.0)}
className="order-2 lg:order-1"
>
<img
src="https://enterprise.nestjs.com/assets/cat-chair.jpg"
alt="Cat in chair"
className="w-full max-w-md mx-auto"
/>
</motion.div>
<motion.div
{...fadeUpPreset(0.3, 1.0)}
className="order-1 lg:order-2"
>
<h2 className="text-4xl md:text-5xl font-bold text-white mb-6">
Team augmentation. By your side at every step
</h2>
<p className="text-xl text-white/90 mb-8 leading-relaxed">
Nest core team members can work directly with your team on a daily basis to help take your project to the next-level. Let us partner with you and your team to develop the most ambitious projects.
</p>
<button className="bg-white text-brand-red px-8 py-3 rounded-full font-medium hover:bg-gray-100 transition-colors">
Contact us to learn more
</button>
</motion.div>
</div>
</div>
</motion.section>
);
}
export default TeamAugmentation;

27
src/index.css Normal file
View File

@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply font-sans antialiased;
}
}
@layer components {
.btn-primary {
@apply bg-brand-red text-white px-8 py-3 rounded-full font-medium hover:bg-brand-red-dark 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-gray-900 transition-colors 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;
}
}

13
src/index.js Normal file
View File

@@ -0,0 +1,13 @@
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(
<React.StrictMode>
<App />
</React.StrictMode>
);

18
tailwind.config.js Normal file
View File

@@ -0,0 +1,18 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
colors: {
'brand-red': '#e53e3e',
'brand-red-dark': '#c53030',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
},
},
plugins: [],
}

5
vercel.json Normal file
View File

@@ -0,0 +1,5 @@
{
"installCommand": "npm install",
"buildCommand": "CI=false npm run build",
"outputDirectory": "build"
}