Initial commit

This commit is contained in:
2026-01-15 12:13:48 +02:00
commit 555c79b332
46 changed files with 2246 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-jobs",
"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: {},
},
}

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

View File

@@ -0,0 +1 @@
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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KICA8aGVhZD4KICAgIDxtZXRhIGNoYXJzZXQ9InV0Zi04IiAvPgogICAgPGxpbmsgcmVsPSJpY29uIiBocmVmPSIvZmF2aWNvbi5pY28iIC8+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEiIC8+CiAgICA8bWV0YSBuYW1lPSJ0aGVtZS1jb2xvciIgY29udGVudD0iIzE1MTkyNCIgLz4KICAgIDxtZXRhCiAgICAgIG5hbWU9ImRlc2NyaXB0aW9uIgogICAgICBjb250ZW50PSJOZXN0SlMgam9icyBpcyB0aGUgYmVzdCBwbGFjZSB0byBoaXJlIG9yIGdldCBoaXJlZCBhcyBOZXN0SlMgZGV2ZWxvcGVyLiBGaW5kIE5lc3RKUyB0YWxlbnQgYW5kIHJlYWNoIHRvIHRob3VzYW5kcyBvZiBkZXZlbG9wZXJzLiIKICAgIC8+CiAgICA8bWV0YSBuYW1lPSJyb2JvdHMiIGNvbnRlbnQ9Im5vb2RwIiAvPgogICAgPGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vam9icy5uZXN0anMuY29tIiAvPgogICAgPG1ldGEgcHJvcGVydHk9Im9nOnVybCIgY29udGVudD0iaHR0cHM6Ly9qb2JzLm5lc3Rqcy5jb20iIC8+CiAgICA8bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2UiIGNvbnRlbnQ9Imh0dHBzOi8vbmVzdGpzLmNvbS9pbWcvbmVzdC1vZy5wbmciPgogICAgPG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+CiAgICA8bWV0YSBuYW1lPSJ0d2l0dGVyOmNhcmQiIGNvbnRlbnQ9InN1bW1hcnlfbGFyZ2VfaW1hZ2UiIC8+CiAgICA8bWV0YQogICAgICBwcm9wZXJ0eT0ib2c6c2l0ZV9uYW1lIgogICAgICBjb250ZW50PSJKb2JzIHwgTmVzdEpTIC0gQSBwcm9ncmVzc2l2ZSBOb2RlLmpzIGZyYW1ld29yayIKICAgIC8+CiAgICA8bWV0YQogICAgICBwcm9wZXJ0eT0ib2c6dGl0bGUiCiAgICAgIGNvbnRlbnQ9IkpvYnMgfCBOZXN0SlMgLSBBIHByb2dyZXNzaXZlIE5vZGUuanMgZnJhbWV3b3JrIgogICAgLz4KICAgIDxtZXRhCiAgICAgIHByb3BlcnR5PSJvZzpkZXNjcmlwdGlvbiIKICAgICAgY29udGVudD0iTmVzdEpTIGpvYnMgaXMgdGhlIGJlc3QgcGxhY2UgdG8gaGlyZSBvciBnZXQgaGlyZWQgYXMgTmVzdEpTIGRldmVsb3Blci4gRmluZCBOZXN0SlMgdGFsZW50IGFuZCByZWFjaCB0byB0aG91c2FuZHMgb2YgZGV2ZWxvcGVycy4iCiAgICAvPgogICAgPG1ldGEKICAgICAgbmFtZT0idHdpdHRlcjp0aXRsZSIKICAgICAgY29udGVudD0iSm9icyB8IE5lc3RKUyAtIEEgcHJvZ3Jlc3NpdmUgTm9kZS5qcyBmcmFtZXdvcmsiCiAgICAvPgogICAgPG1ldGEKICAgICAgbmFtZT0idHdpdHRlcjpkZXNjcmlwdGlvbiIKICAgICAgY29udGVudD0iTmVzdEpTIGpvYnMgaXMgdGhlIGJlc3QgcGxhY2UgdG8gaGlyZSBvciBnZXQgaGlyZWQgYXMgTmVzdEpTIGRldmVsb3Blci4gRmluZCBOZXN0SlMgdGFsZW50IGFuZCByZWFjaCB0byB0aG91c2FuZHMgb2YgZGV2ZWxvcGVycy4iCiAgICAvPgogICAgPGxpbmsgcmVsPSJwcmVjb25uZWN0IiBocmVmPSJodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tIj4KICAgIDxsaW5rIHJlbD0icHJlY29ubmVjdCIgaHJlZj0iaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbSIgY3Jvc3NvcmlnaW4+CiAgICA8bGluayBocmVmPSJodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tL2Nzcz9mYW1pbHk9TW9udHNlcnJhdDozMDAsNDAwLDUwMCw2MDAsNzAwJmRpc3BsYXk9c3dhcCIgcmVsPSJzdHlsZXNoZWV0IiAvPgogICAgPGxpbmsgcmVsPSJhcHBsZS10b3VjaC1pY29uIiBocmVmPSIvbG9nbzE5Mi5wbmciIC8+CiAgICA8bGluayByZWw9Im1hbmlmZXN0IiBocmVmPSIvbWFuaWZlc3QuanNvbiIgLz4KICAgIDxsaW5rIHJlbD0ibWFzay1pY29uIiBocmVmPSIvaW1nL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNlZDI5NDUiIC8+CiAgICA8c2NyaXB0IGRlZmVyIHNyYz0iaHR0cHM6Ly91c2UuZm9udGF3ZXNvbWUuY29tL3JlbGVhc2VzL3Y2LjQuMi9qcy9hbGwuanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdD4KICAgICAgd2luZG93LmRhdGFMYXllciA9IHdpbmRvdy5kYXRhTGF5ZXIgfHwgW107CiAgICAgIGZ1bmN0aW9uIGd0YWcoKXtkYXRhTGF5ZXIucHVzaChhcmd1bWVudHMpO30KICAgICAgZ3RhZygnanMnLCBuZXcgRGF0ZSgpKTsKCiAgICAgIGd0YWcoJ2NvbmZpZycsICdHLVpFM1NHU0dWMjMnKTsKICAgIDwvc2NyaXB0PgogICAgPHRpdGxlPkpvYnMgfCBOZXN0SlMgLSBBIHByb2dyZXNzaXZlIE5vZGUuanMgZnJhbWV3b3JrPC90aXRsZT4KICAgIDxzY3JpcHQgdHlwZT0ibW9kdWxlIiBjcm9zc29yaWdpbiBzcmM9Ii9hc3NldHMvaW5kZXgtRGhyT0wxUzYuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBjcm9zc29yaWdpbiBocmVmPSIvYXNzZXRzL2luZGV4LURFYVhzblhXLmNzcyI+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPG5vc2NyaXB0PllvdSBuZWVkIHRvIGVuYWJsZSBKYXZhU2NyaXB0IHRvIHJ1biB0aGlzIGFwcC48L25vc2NyaXB0PgogICAgPGRpdiBpZD0icm9vdCI+PC9kaXY+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==

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

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

1238
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 JobsSection from './components/JobsSection';
import TeamAugmentation from './components/TeamAugmentation';
import CompaniesSection from './components/CompaniesSection';
import SupportSection from './components/SupportSection';
import Newsletter from './components/Newsletter';
import Footer from './components/Footer';
function App() {
return (
<div className="min-h-screen bg-white">
<Header />
<Hero />
<JobsSection />
<TeamAugmentation />
<CompaniesSection />
<SupportSection />
<Newsletter />
<Footer />
</div>
);
}
export default App;

View File

@@ -0,0 +1,157 @@
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 CompaniesSection = () => {
const shouldReduceMotion = useReducedMotion();
const companies = [
{
name: 'Sanofi',
logo: "/images/sanofi-1768471894979.png",
url: 'https://www.sanofi.com/'
},
{
name: 'Adidas',
logo: "/images/adidas-1768471894841.svg",
url: 'https://adidas.com/'
},
{
name: 'Autodesk',
logo: "/images/autodesk-1768471894939.png",
url: 'https://www.autodesk.com/'
},
{
name: 'Mercedes',
logo: "/images/mercedes-1768471895025.png",
url: 'https://www.mercedes-benz.com/'
},
{
name: 'Red Hat',
logo: "/images/red-hat-1768471894904.svg",
url: 'https://www.redhat.com/'
},
{
name: 'Roche',
logo: "/images/roche-logo-1768471894838.png",
url: 'https://roche.com/'
},
{
name: 'Société Générale',
logo: "/images/societe-generale-logo-1768471895019.png",
url: 'https://www.societegenerale.fr/'
},
{
name: 'Decathlon',
logo: "/images/decathlon-1768471894937.png",
url: 'https://www.decathlon.com/'
},
{
name: 'GitLab',
logo: "/images/gitlab-1768471894835.png",
url: 'https://about.gitlab.com/'
},
{
name: 'JetBrains',
logo: "/images/jetbrains-1768471894878.svg",
url: 'https://www.jetbrains.com/'
},
{
name: 'TotalEnergies',
logo: "/images/totalenergies-1768471894867.svg",
url: 'https://totalenergies.com/'
},
{
name: 'BMW',
logo: "/images/bmw-1768471895184.svg"
},
{
name: 'IBM',
logo: "/images/ibm-1768471894879.svg",
url: 'https://www.ibm.com/'
},
{
name: 'REWE',
logo: "/images/rewe-1768471894868.svg",
url: 'https://www.rewe-digital.com/'
},
{
name: 'Capgemini',
logo: "/images/capgemini-1768471894879.svg",
url: 'https://capgemini.com/'
}
];
const CompanyLogo = ({ company, index }) => {
const logoContent = (
<div className="flex items-center justify-center p-6 bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200">
<img
src={company.logo}
alt={company.name}
className="max-h-12 max-w-32 object-contain filter grayscale hover:grayscale-0 transition-all duration-200"
/>
</div>
);
if (company.url) {
return (
<a href={company.url} target="_blank" rel="noopener noreferrer">
{logoContent}
</a>
);
}
return logoContent;
};
const AnimatedCompanyLogo = ({ company, index }) => {
if (shouldReduceMotion) {
return <CompanyLogo company={company} index={index} />;
}
return (
<motion.div {...fadeUpPreset(index * 0.05, 0.6)}>
<CompanyLogo company={company} index={index} />
</motion.div>
);
};
const sectionContent = (
<section className="py-16 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<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 max-w-3xl mx-auto">
Nest is proudly powering a large ecosystem of enterprises and products out there. Wanna see your logo here? Find out more.
</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-6">
{companies.map((company, index) => (
<AnimatedCompanyLogo key={company.name} company={company} index={index} />
))}
</div>
</div>
</section>
);
if (shouldReduceMotion) {
return sectionContent;
}
return (
<motion.div {...fadeUpPreset(0.1, 1.0)}>
{sectionContent}
</motion.div>
);
};
export default CompaniesSection;

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

@@ -0,0 +1,53 @@
import React from 'react';
import { Github, X } from 'lucide-react';
const Footer = () => {
return (
<footer className="bg-white py-12 border-t border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center">
<div className="flex justify-center space-x-6 mb-6">
<a href="https://github.com/nestjs" className="text-gray-400 hover:text-gray-600 transition-colors">
<Github className="w-6 h-6" />
</a>
<a href="https://twitter.com/nestframework" className="text-gray-400 hover:text-gray-600 transition-colors">
<X className="w-6 h-6" />
</a>
</div>
<div className="space-y-2 text-gray-600">
<p>
Official NestJS Consulting{' '}
<a href="https://trilon.io" className="text-nest-pink hover:text-nest-red transition-colors">
Trilon.io
</a>
</p>
<p>
Copyright © 2017-2026{' '}
<a href="#" className="text-nest-pink hover:text-nest-red transition-colors">
Kamil Mysliwiec
</a>
</p>
<div className="flex justify-center space-x-4 text-sm">
<a href="#" className="text-nest-pink hover:text-nest-red transition-colors">
Terms of Service
</a>
<span>|</span>
<a href="#" className="text-nest-pink hover:text-nest-red transition-colors">
Privacy Policy
</a>
</div>
<p className="text-sm">
Designed by{' '}
<a href="#" className="text-nest-pink hover:text-nest-red transition-colors">
Jakub Staron
</a>
</p>
</div>
</div>
</div>
</footer>
);
};
export default Footer;

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

@@ -0,0 +1,68 @@
import React, { useState } from 'react';
import { Menu, X, ChevronDown, Github } from 'lucide-react';
const Header = () => {
const [isMenuOpen, setIsMenuOpen] = useState(false);
return (
<header className="fixed top-0 left-0 right-0 z-50 bg-black text-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<div className="flex items-center">
<a href="/" className="flex items-center">
<img
src="/images/logo-small-gradient-1768471894765.svg"
alt="NestJS - A progressive Node.js framework"
className="h-8 w-8"
/>
</a>
</div>
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center space-x-8">
<a href="/" className="text-white hover:text-gray-300 transition-colors">HOME</a>
<a href="/jobs" className="text-white hover:text-gray-300 transition-colors">JOBS</a>
<a href="/signin" className="text-white hover:text-gray-300 transition-colors">SIGN IN</a>
<div className="relative group">
<button className="flex items-center text-white hover:text-gray-300 transition-colors">
RESOURCES
<ChevronDown className="ml-1 w-4 h-4" />
</button>
</div>
<a href="https://github.com/nestjs" className="text-white hover:text-gray-300 transition-colors">
<Github className="w-5 h-5" />
</a>
<a href="https://twitter.com/nestframework" className="text-white hover:text-gray-300 transition-colors">
<X className="w-5 h-5" />
</a>
</nav>
{/* Mobile menu button */}
<div className="md:hidden">
<button
onClick={() => setIsMenuOpen(!isMenuOpen)}
className="text-white hover:text-gray-300"
>
{isMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
</button>
</div>
</div>
{/* Mobile Navigation */}
{isMenuOpen && (
<div className="md:hidden">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-black">
<a href="/" className="block text-white hover:text-gray-300 px-3 py-2">HOME</a>
<a href="/jobs" className="block text-white hover:text-gray-300 px-3 py-2">JOBS</a>
<a href="/signin" className="block text-white hover:text-gray-300 px-3 py-2">SIGN IN</a>
<a href="/resources" className="block text-white hover:text-gray-300 px-3 py-2">RESOURCES</a>
</div>
</div>
)}
</div>
</header>
);
};
export default Header;

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

@@ -0,0 +1,85 @@
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 shouldReduceMotion = useReducedMotion();
if (shouldReduceMotion) {
return (
<section className="relative min-h-screen bg-black text-white flex items-center overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-black via-black/90 to-transparent z-10"></div>
<div className="absolute right-0 top-0 w-1/2 h-full">
<div className="w-full h-full bg-gradient-to-l from-gray-800 to-transparent opacity-50"></div>
</div>
<div className="relative z-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-16">
<div className="max-w-2xl">
<h1 className="text-4xl md:text-6xl font-bold mb-6 leading-tight">
Official NestJS job board
</h1>
<p className="text-xl md:text-2xl text-gray-300 mb-8 leading-relaxed">
Discover companies looking for developers with NestJS experience and find your next role.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button className="btn-primary">
Post a job
</button>
<button className="btn-secondary">
Browse open positions
</button>
</div>
</div>
</div>
</section>
);
}
return (
<motion.section
{...fadeUpPreset(0.1, 1.0)}
className="relative min-h-screen bg-black text-white flex items-center overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-r from-black via-black/90 to-transparent z-10"></div>
<div className="absolute right-0 top-0 w-1/2 h-full">
<div className="w-full h-full bg-gradient-to-l from-gray-800 to-transparent opacity-50"></div>
</div>
<div className="relative z-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-16">
<div className="max-w-2xl">
<motion.h1
{...fadeUpPreset(0.2, 1.0)}
className="text-4xl md:text-6xl font-bold mb-6 leading-tight"
>
Official NestJS job board
</motion.h1>
<motion.p
{...fadeUpPreset(0.3, 1.0)}
className="text-xl md:text-2xl text-gray-300 mb-8 leading-relaxed"
>
Discover companies looking for developers with NestJS experience and find your next role.
</motion.p>
<motion.div
{...fadeUpPreset(0.4, 1.0)}
className="flex flex-col sm:flex-row gap-4"
>
<button className="btn-primary">
Post a job
</button>
<button className="btn-secondary">
Browse open positions
</button>
</motion.div>
</div>
</div>
</motion.section>
);
};
export default Hero;

View File

@@ -0,0 +1,255 @@
import React, { useState } from 'react';
import { motion, useReducedMotion } from 'framer-motion';
import { Search, Globe, MapPin, Clock } 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 JobsSection = () => {
const shouldReduceMotion = useReducedMotion();
const [emailSubscription, setEmailSubscription] = useState('');
const jobs = [
{
id: 1,
title: 'Senior Product Engineer',
company: 'Pandektes',
location: 'Remote',
country: '🇩🇰 Denmark',
salary: '$120k - $150k',
timeAgo: '2 hours ago',
logo: "/images/65dc7731-a4bb-4bbe-bc20-7401691a9ec5-1768471895970.png",
featured: false
},
{
id: 2,
title: 'Senior Software Engineer',
company: 'Trilon',
location: 'Remote',
country: '🌏 Worldwide',
timeAgo: '25 days ago',
logo: "/images/612b8b42-9610-43b1-92bd-15373110159f-1768471895436.png",
featured: true
}
];
const expiredJobs = [
{
id: 3,
title: 'Full-Stack Developer Angular/NestJS/PHP/MySQL',
company: 'Nylon Technology',
location: 'Remote',
country: '🇺🇸 United States, Continental...',
salary: '$100k - $130k',
timeAgo: 'a month ago',
logo: "/images/c54da9a9-c7aa-4d9a-838d-1021b684d957-1768471895594.jpeg"
},
{
id: 4,
title: 'Full Stack Typescript Developer (NextJs, NestJs)',
company: 'ClickTech',
location: 'Remote',
country: '🌏 Worldwide',
salary: '$40k - $50k',
timeAgo: '2 months ago',
logo: "/images/3e62a3bc-0bae-4f8b-8e5a-4b14db5ef4ab-1768471895612.jpeg"
},
{
id: 5,
title: 'NestJS Testing Specialist (Freelancer/Consultant)',
company: 'Kapital',
location: '🌏 Worldwide',
timeAgo: '2 months ago',
logo: "/images/6e1385c3-7fd6-4444-8fc4-908d4aef24be-1768471895728.png"
},
{
id: 6,
title: 'Full-Stack Engineer (Mid-Senior) [NestJS, NextJS]',
company: 'OASYS NOW',
location: '🇳🇱 Netherlands, Delft',
salary: '$60k - $80k',
timeAgo: '2 months ago',
logo: "/images/696a0fcf-7bdb-44e2-bb03-dbdb0fb2e18b-1768471895569.jpeg"
},
{
id: 7,
title: 'Senior Backend Engineer',
company: 'Pandektes',
location: 'Remote',
country: '🇩🇰 Denmark, Copenhagen',
salary: '$110k - $140k',
timeAgo: '2 months ago',
logo: "/images/65dc7731-a4bb-4bbe-bc20-7401691a9ec5-1768471895970.png"
},
{
id: 8,
title: 'Backend NestJS Developer',
company: 'ClickTech',
location: 'Remote',
country: '🌏 Worldwide',
salary: '$40k - $60k',
timeAgo: '6 months ago',
logo: "/images/3e62a3bc-0bae-4f8b-8e5a-4b14db5ef4ab-1768471895612.jpeg"
},
{
id: 9,
title: 'Senior Software Engineer',
company: 'Pippen AI',
location: 'Remote',
country: '🇨🇦 Canada, Toronto',
salary: '$70k - $100k',
timeAgo: '6 months ago',
logo: "/images/69388f1e-2dff-444b-9fc4-9f035bbf654f-1768471895570.jpeg"
}
];
const JobCard = ({ job, index }) => {
const cardContent = (
<div className={`job-card ${job.featured ? 'featured-job' : ''}`}>
<div className="flex items-start justify-between mb-4">
<div className="flex items-center space-x-4">
<img
src={job.logo}
alt={job.company}
className="company-logo"
/>
<div>
<h3 className="font-semibold text-lg text-gray-900">{job.title}</h3>
<p className="text-gray-600">at {job.company}</p>
{job.featured && (
<span className="inline-block bg-nest-pink text-white text-xs px-2 py-1 rounded-full mt-1">
FEATURED
</span>
)}
</div>
</div>
<span className="text-sm text-gray-500">{job.timeAgo}</span>
</div>
<div className="flex flex-wrap items-center gap-4 text-sm text-gray-600">
<div className="flex items-center space-x-1">
<MapPin className="w-4 h-4" />
<span>{job.location}</span>
</div>
{job.country && (
<div className="flex items-center space-x-1">
<Globe className="w-4 h-4" />
<span>{job.country}</span>
</div>
)}
{job.salary && (
<div className="flex items-center space-x-1">
<span className="text-green-600 font-medium">💰 {job.salary}</span>
</div>
)}
</div>
</div>
);
if (shouldReduceMotion) {
return cardContent;
}
return (
<motion.div {...fadeUpPreset(index * 0.1, 0.8)}>
{cardContent}
</motion.div>
);
};
const sectionContent = (
<section className="py-16 bg-nest-gray">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
Find your next opportunity
</h2>
<p className="text-xl text-gray-600 mb-8">
Browse through our list of NestJS jobs, find your perfect match and apply. Use filters for more accurate results!
</p>
<div className="bg-nest-pink text-white p-6 rounded-lg mb-8">
<h3 className="text-lg font-semibold mb-4">Get NestJS jobs right to your inbox</h3>
<p className="mb-4">Subscribe to our newsletter to get notified.</p>
<div className="flex flex-col sm:flex-row gap-2 max-w-md mx-auto">
<input
type="email"
placeholder="Enter your email"
value={emailSubscription}
onChange={(e) => setEmailSubscription(e.target.value)}
className="flex-1 px-4 py-2 rounded-lg text-black"
/>
<button className="bg-white text-nest-pink px-6 py-2 rounded-lg font-medium hover:bg-gray-100 transition-colors">
Subscribe
</button>
</div>
</div>
</div>
{/* Search and Filters */}
<div className="bg-white rounded-lg shadow-sm p-6 mb-8">
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div className="relative">
<Search className="absolute left-3 top-3 w-5 h-5 text-gray-400" />
<input
type="text"
placeholder="Search..."
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-nest-pink focus:border-transparent"
/>
</div>
<select className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-nest-pink focus:border-transparent">
<option>Location</option>
<option>Remote</option>
<option>On-site</option>
</select>
<select className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-nest-pink focus:border-transparent">
<option>Seniority</option>
<option>Junior</option>
<option>Mid</option>
<option>Senior</option>
</select>
<select className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-nest-pink focus:border-transparent">
<option>Job type</option>
<option>Full-time</option>
<option>Part-time</option>
<option>Contract</option>
</select>
</div>
</div>
{/* Active Jobs */}
<div className="space-y-4 mb-12">
{jobs.map((job, index) => (
<JobCard key={job.id} job={job} index={index} />
))}
</div>
{/* Expired Jobs */}
<div>
<h3 className="text-2xl font-bold text-gray-900 mb-6">Expired listings</h3>
<div className="space-y-4">
{expiredJobs.map((job, index) => (
<JobCard key={job.id} job={job} index={index} />
))}
</div>
</div>
</div>
</section>
);
if (shouldReduceMotion) {
return sectionContent;
}
return (
<motion.div {...fadeUpPreset(0.1, 1.0)}>
{sectionContent}
</motion.div>
);
};
export default JobsSection;

View File

@@ -0,0 +1,67 @@
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 shouldReduceMotion = useReducedMotion();
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// Handle newsletter subscription
console.log('Newsletter subscription:', email);
setEmail('');
};
const sectionContent = (
<section className="py-16 bg-nest-gray">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
Join our Newsletter
</h2>
<p className="text-xl text-gray-600 mb-8">
Subscribe to stay up to date with the latest Nest updates, features, and videos!
</p>
<form onSubmit={handleSubmit} className="max-w-md mx-auto">
<div className="flex flex-col sm:flex-row gap-2">
<input
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-nest-pink focus:border-transparent"
/>
<button
type="submit"
className="btn-primary flex items-center justify-center space-x-2"
>
<Send className="w-4 h-4" />
<span>Subscribe</span>
</button>
</div>
</form>
</div>
</section>
);
if (shouldReduceMotion) {
return sectionContent;
}
return (
<motion.div {...fadeUpPreset(0.1, 1.0)}>
{sectionContent}
</motion.div>
);
};
export default Newsletter;

View File

@@ -0,0 +1,41 @@
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 sectionContent = (
<section className="py-16 bg-black text-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-3xl md:text-4xl font-bold mb-6">
Does your team need additional support?
</h2>
<p className="text-xl text-gray-300 mb-8 max-w-4xl mx-auto">
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="btn-primary">
Contact us
</button>
</div>
</section>
);
if (shouldReduceMotion) {
return sectionContent;
}
return (
<motion.div {...fadeUpPreset(0.1, 1.0)}>
{sectionContent}
</motion.div>
);
};
export default SupportSection;

View File

@@ -0,0 +1,49 @@
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 shouldReduceMotion = useReducedMotion();
const sectionContent = (
<section className="py-16 bg-nest-pink text-white relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-nest-pink to-nest-red"></div>
<div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
<div>
<h2 className="text-3xl md:text-4xl font-bold mb-6">
Team augmentation. By your side at every step
</h2>
<p className="text-xl mb-8 text-pink-100">
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-nest-pink px-8 py-3 rounded-full font-semibold hover:bg-gray-100 transition-colors">
Contact us to learn more
</button>
</div>
<div className="relative">
<div className="w-full h-64 bg-gradient-to-br from-pink-400 to-red-500 rounded-lg opacity-50"></div>
</div>
</div>
</div>
</section>
);
if (shouldReduceMotion) {
return sectionContent;
}
return (
<motion.div {...fadeUpPreset(0.1, 1.0)}>
{sectionContent}
</motion.div>
);
};
export default TeamAugmentation;

31
src/index.css Normal file
View File

@@ -0,0 +1,31 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply font-sans antialiased;
}
}
@layer components {
.btn-primary {
@apply bg-nest-pink hover:bg-nest-red text-white font-medium px-6 py-3 rounded-full transition-colors duration-200;
}
.btn-secondary {
@apply border border-white text-white hover:bg-white hover:text-black font-medium px-6 py-3 rounded-full transition-all duration-200;
}
.job-card {
@apply bg-white rounded-lg shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow duration-200;
}
.featured-job {
@apply border-l-4 border-nest-pink;
}
.company-logo {
@apply w-12 h-12 rounded-lg object-contain bg-gray-50 p-2;
}
}

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

20
tailwind.config.js Normal file
View File

@@ -0,0 +1,20 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
colors: {
'nest-red': '#e53e3e',
'nest-pink': '#e91e63',
'nest-dark': '#1a1a1a',
'nest-gray': '#f5f5f5'
},
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"
}