Initial commit

This commit is contained in:
2026-01-19 18:06:20 +02:00
commit fafbfedaa5
47 changed files with 2228 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",
"framer-motion": "^11.0.0",
"lucide-react": "^0.400.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

26
src/App.js Normal file
View File

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

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" }
});
const CTA = () => {
const shouldReduce = useReducedMotion();
if (shouldReduce) {
return (
<section className="section-padding bg-gray-900">
<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 max-w-2xl mx-auto">
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-gray-900"
>
<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 max-w-2xl mx-auto"
>
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;

108
src/components/Companies.js Normal file
View File

@@ -0,0 +1,108 @@
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 Companies = () => {
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: 'Swissquote', logo: 'https://enterprise.nestjs.com/assets/logos/swissquote.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-xl text-gray-600 mb-12">
Nest is proudly powering a large ecosystem of enterprises and products out there.
</p>
<p className="text-gray-500 mb-12">
Wanna see your logo here? <a href="#" className="text-brand-red hover:underline">Find out more!</a>
</p>
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 items-center justify-items-center">
{companies.map((company, index) => (
<div key={index} className="flex items-center justify-center h-16 w-32 grayscale hover:grayscale-0 transition-all duration-300">
<img
src={company.logo}
alt={company.name}
className="max-h-12 max-w-full object-contain"
/>
</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-xl text-gray-600 mb-12"
>
Nest is proudly powering a large ecosystem of enterprises and products out there.
</motion.p>
<motion.p
{...fadeUpPreset(0.4, 1.0)}
className="text-gray-500 mb-12"
>
Wanna see your logo here? <a href="#" className="text-brand-red hover:underline">Find out more!</a>
</motion.p>
<motion.div
{...fadeUpPreset(0.5, 1.0)}
className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 items-center justify-items-center"
>
{companies.map((company, index) => (
<motion.div
key={index}
{...fadeUpPreset(0.6 + index * 0.05, 0.8)}
className="flex items-center justify-center h-16 w-32 grayscale hover:grayscale-0 transition-all duration-300"
>
<img
src={company.logo}
alt={company.name}
className="max-h-12 max-w-full object-contain"
/>
</motion.div>
))}
</motion.div>
</div>
</motion.section>
);
};
export default Companies;

View File

@@ -0,0 +1,96 @@
import React from 'react';
import { motion, useReducedMotion } from 'framer-motion';
import { Check } 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 Features = () => {
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-xl text-gray-600 mb-8">
We work alongside you to meet your deadlines while avoiding costly tech debt. Challenging issue? We've got you covered.
</p>
<p className="text-gray-600 mb-8">
Our Nest core team got you covered! Nest core team members will help you define best practices and choose the right strategy for your goals.
</p>
<a href="#" className="text-brand-red font-medium hover:underline">
Contact us to learn more
</a>
</div>
<div className="space-y-4">
{features.map((feature, index) => (
<div key={index} className="flex items-start space-x-3">
<Check 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-xl text-gray-600 mb-8">
We work alongside you to meet your deadlines while avoiding costly tech debt. Challenging issue? We've got you covered.
</p>
<p className="text-gray-600 mb-8">
Our Nest core team got you covered! Nest core team members will help you define best practices and choose the right strategy for your goals.
</p>
<a href="#" className="text-brand-red font-medium hover:underline">
Contact us to learn more
</a>
</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.1, 0.8)}
className="flex items-start space-x-3"
>
<Check 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 Features;

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

@@ -0,0 +1,84 @@
import React, { useState } from 'react';
import { Github, X, Send } from 'lucide-react';
const Footer = () => {
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log('Newsletter signup:', email);
setEmail('');
};
return (
<footer className="bg-gray-100 py-12">
<div className="container-custom">
{/* Newsletter Section */}
<div className="bg-white rounded-2xl p-8 mb-12">
<div className="max-w-2xl mx-auto text-center">
<h3 className="text-2xl font-bold text-gray-900 mb-4">
Join our Newsletter
</h3>
<p className="text-gray-600 mb-6">
Stay up to date with the latest NestJS features, tutorials, and news.
</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 hover:bg-brand-red-dark transition-colors flex items-center justify-center gap-2"
>
<Send className="w-4 h-4" />
Subscribe
</button>
</form>
</div>
</div>
{/* Footer Content */}
<div className="text-center space-y-4">
{/* Social Links */}
<div className="flex justify-center space-x-6">
<a href="#" className="text-gray-400 hover:text-gray-600 transition-colors">
<Github className="w-6 h-6" />
</a>
<a href="#" className="text-gray-400 hover:text-gray-600 transition-colors">
<X className="w-6 h-6" />
</a>
</div>
{/* Company Info */}
<div className="space-y-2 text-sm text-gray-500">
<p>
Official NestJS Consulting{' '}
<a href="#" className="text-brand-red hover:underline">
Trilon.io
</a>
</p>
<p>
Copyright © 2017- 2024{' '}
<a href="#" className="text-brand-red hover:underline">
Kamil Myśliwiec
</a>
</p>
<p>
Designed by{' '}
<a href="#" className="text-brand-red hover:underline">
Jakub Staron
</a>
</p>
</div>
</div>
</div>
</footer>
);
};
export default Footer;

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

@@ -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 (
<header className="fixed top-0 left-0 right-0 z-50 bg-gray-900/95 backdrop-blur-sm border-b border-gray-800">
<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 7v10c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V7l-10-5z"/>
</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">
<button
className="flex items-center text-white hover:text-brand-red transition-colors"
onClick={() => setIsResourcesOpen(!isResourcesOpen)}
>
<span className="bg-brand-red text-white text-xs px-2 py-1 rounded mr-2">
NEW
</span>
RESOURCES
<ChevronDown className="ml-1 w-4 h-4" />
</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 py-4 border-t border-gray-800">
<nav className="flex flex-col space-y-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">
<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;

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

@@ -0,0 +1,95 @@
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 Hero = () => {
const shouldReduce = useReducedMotion();
if (shouldReduce) {
return (
<section className="relative min-h-screen bg-gray-900 flex items-center overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-gray-900 via-gray-900/90 to-transparent z-10"></div>
<div className="absolute inset-0 bg-hero-pattern"></div>
<div className="absolute right-0 top-0 w-1/2 h-full">
<img
src="https://enterprise.nestjs.com/assets/hero-cat.jpg"
alt="Cat looking focused"
className="w-full h-full object-cover opacity-80"
/>
</div>
<div className="container-custom relative z-20">
<div className="max-w-2xl">
<h1 className="text-5xl md:text-6xl lg:text-7xl font-bold text-white mb-6 leading-tight">
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-gray-900 flex items-center overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-gray-900 via-gray-900/90 to-transparent z-10"></div>
<div className="absolute inset-0 bg-hero-pattern"></div>
<div className="absolute right-0 top-0 w-1/2 h-full">
<img
src="https://enterprise.nestjs.com/assets/hero-cat.jpg"
alt="Cat looking focused"
className="w-full h-full object-cover opacity-80"
/>
</div>
<div className="container-custom relative z-20">
<div className="max-w-2xl">
<motion.h1
{...fadeUpPreset(0.2, 0.8)}
className="text-5xl md:text-6xl lg:text-7xl font-bold text-white mb-6 leading-tight"
>
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;

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

@@ -0,0 +1,126 @@
import React from 'react';
import { motion, useReducedMotion } from 'framer-motion';
import { Users, Settings, Zap, Search, Target, Award } 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 Services = () => {
const shouldReduce = useReducedMotion();
const services = [
{
icon: Users,
title: "DEVELOPMENT",
description: "Achieve your goals faster with Nest experts on your side. Challenging issues right by your side."
},
{
icon: Settings,
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 enhancing best practices."
},
{
icon: Target,
title: "LONG-TERM SUPPORT (LTS)",
description: "The peace of mind with Nest long-term support (LTS), priority fixes, upgrade assistance, and live troubleshooting."
},
{
icon: Award,
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-xl 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-2xl 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-xl 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-2xl 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,78 @@
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 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="relative">
<div className="bg-white rounded-3xl p-8 max-w-sm mx-auto">
<img
src="https://enterprise.nestjs.com/assets/team-cat.jpg"
alt="Cat in modern chair"
className="w-full h-64 object-cover rounded-2xl"
/>
</div>
</div>
<div className="text-white">
<h2 className="text-4xl md:text-5xl font-bold mb-6">
Team augmentation. By your side at every step
</h2>
<p className="text-xl mb-8 opacity-90">
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">
Connect 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="relative">
<div className="bg-white rounded-3xl p-8 max-w-sm mx-auto">
<img
src="https://enterprise.nestjs.com/assets/team-cat.jpg"
alt="Cat in modern chair"
className="w-full h-64 object-cover rounded-2xl"
/>
</div>
</motion.div>
<motion.div {...fadeUpPreset(0.3, 1.0)} className="text-white">
<h2 className="text-4xl md:text-5xl font-bold mb-6">
Team augmentation. By your side at every step
</h2>
<p className="text-xl mb-8 opacity-90">
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">
Connect us to learn more
</button>
</motion.div>
</div>
</div>
</motion.section>
);
};
export default TeamAugmentation;

37
src/index.css Normal file
View File

@@ -0,0 +1,37 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply font-sans antialiased;
}
h1, h2, h3, h4, h5, h6 {
@apply font-bold;
}
}
@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;
}
}
@layer utilities {
.text-gradient {
@apply bg-gradient-to-r from-brand-red to-pink-500 bg-clip-text text-transparent;
}
}

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>
);

41
tailwind.config.js Normal file
View File

@@ -0,0 +1,41 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
colors: {
'brand-red': {
DEFAULT: '#E53E3E',
dark: '#C53030',
light: '#FC8181'
},
'brand-pink': {
DEFAULT: '#ED64A6',
dark: '#D53F8C',
light: '#F687B3'
},
'gray': {
50: '#F7FAFC',
100: '#EDF2F7',
200: '#E2E8F0',
300: '#CBD5E0',
400: '#A0AEC0',
500: '#718096',
600: '#4A5568',
700: '#2D3748',
800: '#1A202C',
900: '#171923'
}
},
fontFamily: {
'sans': ['Inter', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif']
},
backgroundImage: {
'hero-pattern': 'linear-gradient(135deg, rgba(229, 62, 62, 0.1) 0%, rgba(237, 100, 166, 0.1) 100%)'
}
},
},
plugins: [],
}

5
vercel.json Normal file
View File

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