setup intl for multi language website and make hero and services and projects components in home dynamic and optimized

This commit is contained in:
Pouya Defaei
2026-04-25 13:27:13 +03:30
parent d1d9c309f8
commit 8c051c3533
28 changed files with 1257 additions and 218 deletions

View File

@@ -1,8 +1,26 @@
import type { NextConfig } from "next"; const createNextIntlPlugin = require("next-intl/plugin");
const nextConfig: NextConfig = { const withNextIntl = createNextIntlPlugin("./src/i18n.ts");
output: "standalone",
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
unoptimized: true,
remotePatterns: [
{
protocol: "http",
hostname: "127.0.0.1", // Changed from localhost
port: "4000",
pathname: "/uploads/**",
},
{
protocol: "http",
hostname: "localhost",
port: "4000", // Updated to match your environment variables
pathname: "/uploads/**",
},
],
},
}; };
export default nextConfig; module.exports = withNextIntl(nextConfig);

710
package-lock.json generated
View File

@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"lucide-react": "^1.8.0", "lucide-react": "^1.8.0",
"next": "16.2.4", "next": "16.2.4",
"next-intl": "^4.9.1",
"react": "19.2.4", "react": "19.2.4",
"react-dom": "19.2.4" "react-dom": "19.2.4"
}, },
@@ -68,6 +69,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0", "@babel/generator": "^7.29.0",
@@ -454,6 +456,36 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@formatjs/fast-memoize": {
"version": "3.1.2",
"resolved": "https://mirror-npm.runflare.com/@formatjs/fast-memoize/-/fast-memoize-3.1.2.tgz",
"integrity": "sha512-vPnriihkfK0lzoQGaXq+qXH23VsYyansRTkTgo2aTG0k1NjLFyZimFVdfj4C9JkSE5dm7CEngcQ5TTc1yAyBfQ==",
"license": "MIT"
},
"node_modules/@formatjs/icu-messageformat-parser": {
"version": "3.5.4",
"resolved": "https://mirror-npm.runflare.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.4.tgz",
"integrity": "sha512-JVY39ROgLt+pIYngo6piyj4OVfZmXs/2FkC4wLS+ql1Eig/sGJKB7YwDO/5bkJFkfwaFAeIpgEiJc8hiYxNalw==",
"license": "MIT",
"dependencies": {
"@formatjs/icu-skeleton-parser": "2.1.4"
}
},
"node_modules/@formatjs/icu-skeleton-parser": {
"version": "2.1.4",
"resolved": "https://mirror-npm.runflare.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.4.tgz",
"integrity": "sha512-8bSFZbrlvGX11ywMZxtgkPBt5Q8/etyts7j7j+GWpOVK1g43zwMIH3LZxk43HAtEP7L/jtZ+OZaMiFTOiBj9CA==",
"license": "MIT"
},
"node_modules/@formatjs/intl-localematcher": {
"version": "0.8.3",
"resolved": "https://mirror-npm.runflare.com/@formatjs/intl-localematcher/-/intl-localematcher-0.8.3.tgz",
"integrity": "sha512-pHUjWb9NuhnMs8+PxQdzBtZRFJHlGhrURGAbm6Ltwl82BFajeuiIR3jblSa7ia3r62rXe/0YtVpUG3xWr5bFCA==",
"license": "MIT",
"dependencies": {
"@formatjs/fast-memoize": "3.1.2"
}
},
"node_modules/@humanfs/core": { "node_modules/@humanfs/core": {
"version": "0.19.2", "version": "0.19.2",
"resolved": "https://mirror-npm.runflare.com/@humanfs/core/-/core-0.19.2.tgz", "resolved": "https://mirror-npm.runflare.com/@humanfs/core/-/core-0.19.2.tgz",
@@ -1241,6 +1273,313 @@
"node": ">=12.4.0" "node": ">=12.4.0"
} }
}, },
"node_modules/@parcel/watcher": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher/-/watcher-2.5.6.tgz",
"integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"detect-libc": "^2.0.3",
"is-glob": "^4.0.3",
"node-addon-api": "^7.0.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.6",
"@parcel/watcher-darwin-arm64": "2.5.6",
"@parcel/watcher-darwin-x64": "2.5.6",
"@parcel/watcher-freebsd-x64": "2.5.6",
"@parcel/watcher-linux-arm-glibc": "2.5.6",
"@parcel/watcher-linux-arm-musl": "2.5.6",
"@parcel/watcher-linux-arm64-glibc": "2.5.6",
"@parcel/watcher-linux-arm64-musl": "2.5.6",
"@parcel/watcher-linux-x64-glibc": "2.5.6",
"@parcel/watcher-linux-x64-musl": "2.5.6",
"@parcel/watcher-win32-arm64": "2.5.6",
"@parcel/watcher-win32-ia32": "2.5.6",
"@parcel/watcher-win32-x64": "2.5.6"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
"integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
"integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
"integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
"integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
"integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
"integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
"integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
"integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
"integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
"integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
"integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
"integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.6",
"resolved": "https://mirror-npm.runflare.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
"integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher/node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://mirror-npm.runflare.com/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@rtsao/scc": { "node_modules/@rtsao/scc": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirror-npm.runflare.com/@rtsao/scc/-/scc-1.1.0.tgz", "resolved": "https://mirror-npm.runflare.com/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -1248,6 +1587,210 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@schummar/icu-type-parser": {
"version": "1.21.5",
"resolved": "https://mirror-npm.runflare.com/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz",
"integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==",
"license": "MIT"
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.30.tgz",
"integrity": "sha512-VvpP+vq08HmGYewMWvrdsxh9s2lthz/808zXm8Yu5kaqeR8Yia2b0eYXleHQ3VAjoStUDk6LzTheBW9KXYQdMA==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.30.tgz",
"integrity": "sha512-WiJA0hiZI3nwQAO6mu5RqigtWGDtth4Hiq6rbZxAaQyhIcqKIg5IoMRc1Y071lrNJn29eEDMC86Rq58xgUxlDg==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.30.tgz",
"integrity": "sha512-YANuFUo48kIT6plJgCD0keae9HFXfjxsbvsgevqc0hr/07X/p7sAWTFOGYEc2SXcASaK7UvuQqzlbW8pr7R79g==",
"cpu": [
"arm"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.30.tgz",
"integrity": "sha512-VndG8jaR4ugY6u+iVOT0Q+d2fZd7sLgjPgN8W/Le+3EbZKl+cRfFxV7Eoz4gfLqhmneZPdcIzf9T3LkgkmqNLg==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.30.tgz",
"integrity": "sha512-1SYGs2l0Yyyi0pR/P/NKz/x0kqxkoiw+BXeJjLUdecSk/KasncWlJrc6hOvFSgKHOBrzgM5jwuluKtlT8dnrcA==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-ppc64-gnu": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.30.tgz",
"integrity": "sha512-TXREtiXeRhbfDFbmhnkIsXpKfzbfT73YkV2ZF6w0sfxgjC5zI2ZAbaCOq25qxvegofj2K93DtOpm9RLaBgqR2g==",
"cpu": [
"ppc64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-s390x-gnu": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.30.tgz",
"integrity": "sha512-DCR2YYeyd6DQE4OuDhImouuNcjXEiEdnn1Y0DyGteugPEDvVuvYk8Xddi+4o2SgWH6jiW8/I+3emZvbep1NC+g==",
"cpu": [
"s390x"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.30.tgz",
"integrity": "sha512-5Pizw3NgfOJ5BJOBK8TIRa59xFW2avESTOBDPTAYwZYa1JNDs+KMF9lUfjJiJLM5HiMs/wPheA9eiT0q9m2AoA==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-musl": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.30.tgz",
"integrity": "sha512-qyqydP/wyH8alcIP4a2hnGSjHLJjm9H7yDFup+CPy9oTahFgLLwnNcv5UHXqO2Qs3AIND+cls5f/Bb6hqpxdgA==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.30.tgz",
"integrity": "sha512-CaQENgDHVGOg1mSF5sQVgvfFHG9kjMor2rkLMLeLOkfZYNj13ppnJ9+lfaBZLZUMMbnlGQnavCJb8PVBUOso7Q==",
"cpu": [
"arm64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.30.tgz",
"integrity": "sha512-30VdLeGk6fugiUs/kUdJ/pAg7z/zpvVbR11RH60jZ0Z42WIeIniYx0rLEWN7h/pKJ3CopqsQ3RsogCAkRKiA2g==",
"cpu": [
"ia32"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.30.tgz",
"integrity": "sha512-4iObHPR+Q4oDY110EF5SF5eIaaVJNpMdG9C0q3Q92BsJ5y467uHz7sYQhP60WYlLFsLQ1el2YrIPUItUAQGOKg==",
"cpu": [
"x64"
],
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://mirror-npm.runflare.com/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"license": "Apache-2.0"
},
"node_modules/@swc/helpers": { "node_modules/@swc/helpers": {
"version": "0.5.15", "version": "0.5.15",
"resolved": "https://mirror-npm.runflare.com/@swc/helpers/-/helpers-0.5.15.tgz", "resolved": "https://mirror-npm.runflare.com/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1257,6 +1800,15 @@
"tslib": "^2.8.0" "tslib": "^2.8.0"
} }
}, },
"node_modules/@swc/types": {
"version": "0.1.26",
"resolved": "https://mirror-npm.runflare.com/@swc/types/-/types-0.1.26.tgz",
"integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==",
"license": "Apache-2.0",
"dependencies": {
"@swc/counter": "^0.1.3"
}
},
"node_modules/@tailwindcss/node": { "node_modules/@tailwindcss/node": {
"version": "4.2.2", "version": "4.2.2",
"resolved": "https://mirror-npm.runflare.com/@tailwindcss/node/-/node-4.2.2.tgz", "resolved": "https://mirror-npm.runflare.com/@tailwindcss/node/-/node-4.2.2.tgz",
@@ -1640,6 +2192,7 @@
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.2.2" "csstype": "^3.2.2"
} }
@@ -1699,6 +2252,7 @@
"integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.58.2", "@typescript-eslint/scope-manager": "8.58.2",
"@typescript-eslint/types": "8.58.2", "@typescript-eslint/types": "8.58.2",
@@ -2224,6 +2778,7 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -2567,6 +3122,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.10.12", "baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782", "caniuse-lite": "^1.0.30001782",
@@ -2866,7 +3422,6 @@
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://mirror-npm.runflare.com/detect-libc/-/detect-libc-2.1.2.tgz", "resolved": "https://mirror-npm.runflare.com/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -3134,6 +3689,7 @@
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -3319,6 +3875,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@rtsao/scc": "^1.1.0", "@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9", "array-includes": "^3.1.9",
@@ -3980,6 +4537,21 @@
"hermes-estree": "0.25.1" "hermes-estree": "0.25.1"
} }
}, },
"node_modules/icu-minify": {
"version": "4.9.1",
"resolved": "https://mirror-npm.runflare.com/icu-minify/-/icu-minify-4.9.1.tgz",
"integrity": "sha512-6NkfF9GHHFouqnz+wuiLjCWQiyxoEyJ5liUv4Jxxo/8wyhV7MY0L0iTEGDAVEa4aAD58WqTxFMa20S5nyMjwNw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"license": "MIT",
"dependencies": {
"@formatjs/icu-messageformat-parser": "^3.4.0"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://mirror-npm.runflare.com/ignore/-/ignore-5.3.2.tgz", "resolved": "https://mirror-npm.runflare.com/ignore/-/ignore-5.3.2.tgz",
@@ -4032,6 +4604,16 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/intl-messageformat": {
"version": "11.2.1",
"resolved": "https://mirror-npm.runflare.com/intl-messageformat/-/intl-messageformat-11.2.1.tgz",
"integrity": "sha512-1gAVEUt3wEPvTqML4Fsw9klZV5j0vszQxayP/fi6gUroAc8AUHiNaisBKLWxybL1AdWq1mP07YV1q8v4N92ilQ==",
"license": "BSD-3-Clause",
"dependencies": {
"@formatjs/fast-memoize": "3.1.2",
"@formatjs/icu-messageformat-parser": "3.5.4"
}
},
"node_modules/is-array-buffer": { "node_modules/is-array-buffer": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://mirror-npm.runflare.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "resolved": "https://mirror-npm.runflare.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4194,7 +4776,6 @@
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://mirror-npm.runflare.com/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://mirror-npm.runflare.com/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@@ -4240,7 +4821,6 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://mirror-npm.runflare.com/is-glob/-/is-glob-4.0.3.tgz", "resolved": "https://mirror-npm.runflare.com/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"is-extglob": "^2.1.1" "is-extglob": "^2.1.1"
@@ -5047,6 +5627,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://mirror-npm.runflare.com/negotiator/-/negotiator-1.0.0.tgz",
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/next": { "node_modules/next": {
"version": "16.2.4", "version": "16.2.4",
"resolved": "https://mirror-npm.runflare.com/next/-/next-16.2.4.tgz", "resolved": "https://mirror-npm.runflare.com/next/-/next-16.2.4.tgz",
@@ -5100,6 +5689,83 @@
} }
} }
}, },
"node_modules/next-intl": {
"version": "4.9.1",
"resolved": "https://mirror-npm.runflare.com/next-intl/-/next-intl-4.9.1.tgz",
"integrity": "sha512-N7ga0CjtYcdxNvaKNIi6eJ2mmatlHK5hp8rt0YO2Omoc1m0gean242/Ukdj6+gJNiReBVcYIjK0HZeNx7CV1ug==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"license": "MIT",
"dependencies": {
"@formatjs/intl-localematcher": "^0.8.1",
"@parcel/watcher": "^2.4.1",
"@swc/core": "^1.15.2",
"icu-minify": "^4.9.1",
"negotiator": "^1.0.0",
"next-intl-swc-plugin-extractor": "^4.9.1",
"po-parser": "^2.1.1",
"use-intl": "^4.9.1"
},
"peerDependencies": {
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/next-intl-swc-plugin-extractor": {
"version": "4.9.1",
"resolved": "https://mirror-npm.runflare.com/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.9.1.tgz",
"integrity": "sha512-8whJJ6oxJz8JqkHarggmmuEDyXgC7nEnaPhZD91CJwEWW4xp0AST3Mw17YxvHyP2vAF3taWfFbs1maD+WWtz3w==",
"license": "MIT"
},
"node_modules/next-intl/node_modules/@swc/core": {
"version": "1.15.30",
"resolved": "https://mirror-npm.runflare.com/@swc/core/-/core-1.15.30.tgz",
"integrity": "sha512-R8VQbQY1BZcbIF2p3gjlTCwAQzx1A194ugWfwld5y+WgVVWqVKm7eURGGOVbQVubgKWzidP2agomBbg96rZilQ==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.26"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
"@swc/core-darwin-arm64": "1.15.30",
"@swc/core-darwin-x64": "1.15.30",
"@swc/core-linux-arm-gnueabihf": "1.15.30",
"@swc/core-linux-arm64-gnu": "1.15.30",
"@swc/core-linux-arm64-musl": "1.15.30",
"@swc/core-linux-ppc64-gnu": "1.15.30",
"@swc/core-linux-s390x-gnu": "1.15.30",
"@swc/core-linux-x64-gnu": "1.15.30",
"@swc/core-linux-x64-musl": "1.15.30",
"@swc/core-win32-arm64-msvc": "1.15.30",
"@swc/core-win32-ia32-msvc": "1.15.30",
"@swc/core-win32-x64-msvc": "1.15.30"
},
"peerDependencies": {
"@swc/helpers": ">=0.5.17"
},
"peerDependenciesMeta": {
"@swc/helpers": {
"optional": true
}
}
},
"node_modules/next/node_modules/postcss": { "node_modules/next/node_modules/postcss": {
"version": "8.4.31", "version": "8.4.31",
"resolved": "https://mirror-npm.runflare.com/postcss/-/postcss-8.4.31.tgz", "resolved": "https://mirror-npm.runflare.com/postcss/-/postcss-8.4.31.tgz",
@@ -5128,6 +5794,12 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://mirror-npm.runflare.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"license": "MIT"
},
"node_modules/node-exports-info": { "node_modules/node-exports-info": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://mirror-npm.runflare.com/node-exports-info/-/node-exports-info-1.6.0.tgz", "resolved": "https://mirror-npm.runflare.com/node-exports-info/-/node-exports-info-1.6.0.tgz",
@@ -5404,6 +6076,12 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/po-parser": {
"version": "2.1.1",
"resolved": "https://mirror-npm.runflare.com/po-parser/-/po-parser-2.1.1.tgz",
"integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==",
"license": "MIT"
},
"node_modules/possible-typed-array-names": { "node_modules/possible-typed-array-names": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://mirror-npm.runflare.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "resolved": "https://mirror-npm.runflare.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -5501,6 +6179,7 @@
"resolved": "https://mirror-npm.runflare.com/react/-/react-19.2.4.tgz", "resolved": "https://mirror-npm.runflare.com/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -5510,6 +6189,7 @@
"resolved": "https://mirror-npm.runflare.com/react-dom/-/react-dom-19.2.4.tgz", "resolved": "https://mirror-npm.runflare.com/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.27.0" "scheduler": "^0.27.0"
}, },
@@ -6201,6 +6881,7 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -6363,6 +7044,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -6497,6 +7179,27 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"node_modules/use-intl": {
"version": "4.9.1",
"resolved": "https://mirror-npm.runflare.com/use-intl/-/use-intl-4.9.1.tgz",
"integrity": "sha512-iGVV/xFYlhe3btafRlL8RPLD2Jsuet4yqn9DR6LWWbMhULsJnXgLonDkzDmsAIBIwFtk02oJuX/Ox2vwHKF+UQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"license": "MIT",
"dependencies": {
"@formatjs/fast-memoize": "^3.1.0",
"@schummar/icu-type-parser": "1.21.5",
"icu-minify": "^4.9.1",
"intl-messageformat": "^11.1.0"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://mirror-npm.runflare.com/which/-/which-2.0.2.tgz", "resolved": "https://mirror-npm.runflare.com/which/-/which-2.0.2.tgz",
@@ -6638,6 +7341,7 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }

View File

@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"lucide-react": "^1.8.0", "lucide-react": "^1.8.0",
"next": "16.2.4", "next": "16.2.4",
"next-intl": "^4.9.1",
"react": "19.2.4", "react": "19.2.4",
"react-dom": "19.2.4" "react-dom": "19.2.4"
}, },

View File

@@ -29,7 +29,6 @@
} }
body { body {
direction: rtl;
background-color: var(--background); background-color: var(--background);
color: var(--foreground); color: var(--foreground);
} }

View File

@@ -0,0 +1,40 @@
import type { Metadata } from "next";
import "./globals.css";
import localFont from "next/font/local";
import { NextIntlClientProvider } from "next-intl";
import { getMessages } from "next-intl/server";
import Navbar from "@/components/shared/Navbar";
import { notFound } from "next/navigation";
const modam = localFont({
src: "../../../public/fonts/ModamWeb-Bold.woff2",
weight: "100 900",
});
export const metadata: Metadata = {
title: "رایین شبکه | توسعه نرم‌افزار",
description: "ساخت اپلیکیشن‌های وب مدرن و سیستم‌های سازمانی",
};
const locales = ["fa", "en", "ar"];
export default async function LocaleLayout({ children, params }: { children: React.ReactNode; params: Promise<{ locale: string }> }) {
const { locale } = await params;
if (!locales.includes(locale)) {
notFound();
}
const messages = await getMessages({ locale });
return (
<html lang={locale} dir={locale === "en" ? "ltr" : "rtl"}>
<body className={`${modam.className} flex flex-col min-h-screen bg-bg text-foreground`}>
<NextIntlClientProvider messages={messages}>
<Navbar />
{children}
</NextIntlClientProvider>
</body>
</html>
);
}

View File

@@ -1,24 +1,28 @@
import BentoServices from "@/components/home/BentoServices";
import HomeAcademy from "@/components/home/HomeAcademy"; import HomeAcademy from "@/components/home/HomeAcademy";
import HomeHero from "@/components/home/HomeHero"; import Hero from "@/components/home/hero/Hero";
import HomeProjects from "@/components/home/HomeProjects";
import TechMarquee from "@/components/home/TechMarquee";
import Consultation from "@/components/network/Consultation"; import Consultation from "@/components/network/Consultation";
import ContactFooter from "@/components/network/ContactFooter"; import ContactFooter from "@/components/network/ContactFooter";
import Services from "@/components/home/Services";
import Projects from "@/components/home/Projects";
import { BACKEND_URL_LOCAL } from "@/utilities/constants/urls.constant";
import { Portfolio } from "@/utilities/types/portfolio.type";
export default async function HomePage({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params;
const latestPortfolios: Portfolio[] = await fetch(`${BACKEND_URL_LOCAL}/portfolios/latest/${locale}`)
.then((res) => res.json())
.then((res) => res.data);
export default function HomePage() {
return ( return (
<div className="min-h-screen bg-[#0B1120] text-white font-sans selection:bg-orange-500/30 rtl" dir="rtl"> <div className="min-h-screen bg-[#0B1120] text-white font-sans selection:bg-orange-500/30">
{/* Background Glow */}
<div className="fixed top-0 inset-x-0 h-[500px] bg-gradient-to-b from-orange-500/5 via-transparent to-transparent pointer-events-none -z-10"></div> <div className="fixed top-0 inset-x-0 h-[500px] bg-gradient-to-b from-orange-500/5 via-transparent to-transparent pointer-events-none -z-10"></div>
<main className="flex flex-col gap-24 pt-32 pb-12"> <main className="flex flex-col gap-24 pt-32 pb-12">
<HomeHero /> <Hero />
<TechMarquee />
<div className="w-full px-4 mx-auto space-y-32 max-w-7xl sm:px-6 lg:px-8"> <div className="w-full px-4 mx-auto space-y-32 max-w-7xl sm:px-6 lg:px-8">
<BentoServices /> <Services />
<HomeProjects /> <Projects data={latestPortfolios} />
<HomeAcademy /> <HomeAcademy />
<div> <div>
<Consultation /> <Consultation />

View File

@@ -1,29 +0,0 @@
import type { Metadata } from "next";
import "./globals.css";
import localFont from "next/font/local";
import Navbar from "@/components/shared/Navbar";
const modam = localFont({
src: "../../public/fonts/ModamWeb-Bold.woff2",
weight: "100 900",
});
export const metadata: Metadata = {
title: "رایین شبکه | توسعه نرم‌افزار",
description: "ساخت اپلیکیشن‌های وب مدرن و سیستم‌های سازمانی",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="fa-ir" className={modam.className}>
<body className="flex flex-col min-h-screen bg-bg text-foreground">
<Navbar />
{children}
</body>
</html>
);
}

View File

@@ -1,37 +0,0 @@
import React from "react";
import { ChevronLeft } from "lucide-react";
export default function HomeHero() {
return (
<section className="flex flex-col items-center justify-center max-w-4xl px-4 mx-auto text-center">
{/* Top Badge */}
<div className="inline-flex items-center gap-2 px-4 py-2 mb-8 text-sm text-orange-400 border rounded-full border-orange-500/20 bg-orange-500/10">
<span className="w-2 h-2 bg-orange-500 rounded-full animate-pulse"></span>
معماری سیستمهای مقیاسپذیر
</div>
{/* Main Title */}
<h1 className="mb-6 text-5xl font-bold leading-tight md:text-7xl">
ما گرههای فنی شما را
<br />
باز میکنیم
</h1>
{/* Subtitle */}
<p className="max-w-2xl mb-10 text-lg leading-relaxed text-gray-400 md:text-xl">
ترکیبی از اقتدار مهندسی در زیرساخت و نوآوری مدرن در توسعه نرمافزار، از راهاندازی شبکههای پیچیده تا توسعه پلتفرمهای ابری سفارشی.
</p>
{/* CTA Buttons */}
<div className="flex flex-col items-center gap-4 sm:flex-row">
<button className="flex items-center justify-center w-full gap-2 px-8 py-3 font-medium text-white transition-colors bg-orange-600 rounded-lg sm:w-auto hover:bg-orange-500">
دریافت مشاوره رایگان
<ChevronLeft className="w-4 h-4" />
</button>
<button className="flex items-center justify-center w-full px-8 py-3 font-medium text-white transition-colors border rounded-lg sm:w-auto border-slate-700 bg-slate-800/50 hover:bg-slate-800">
مشاهده نمونهکارها
</button>
</div>
</section>
);
}

View File

@@ -1,92 +0,0 @@
"use client";
import React, { useState } from "react";
import { ArrowUpLeft, FolderKanban } from "lucide-react";
const projectsData = [
{
id: 1,
title: "ارتقای زیرساخت شبکه هلدینگ دارویی",
category: "شبکه",
description: "طراحی مجدد توپولوژی شبکه و پیاده‌سازی فایروال‌های سخت‌افزاری برای امنیت حداکثری.",
image: "bg-slate-800", // در پروژه واقعی از آدرس تصویر استفاده کنید
},
{
id: 2,
title: "پلتفرم مدیریت منابع انسانی (HRM)",
category: "نرم‌افزار",
description: "توسعه سیستم جامع مدیریت پرسنل با استفاده از Next.js و .NET Core.",
image: "bg-slate-800",
},
{
id: 3,
title: "طراحی هویت بصری استارتاپ فین‌تک",
category: "برندینگ",
description: "طراحی کامل UI/UX اپلیکیشن موبایل و دیزاین سیستم سازمانی.",
image: "bg-slate-800",
},
];
const tabs = ["همه", "شبکه", "نرم‌افزار", "برندینگ"];
export default function HomeProjects() {
const [activeTab, setActiveTab] = useState("همه");
const filteredProjects = projectsData.filter((project) => (activeTab === "همه" ? true : project.category === activeTab));
return (
<section className="py-12 border-t border-slate-800/50">
<div className="flex flex-col justify-between gap-6 mb-12 md:flex-row md:items-end">
<div>
<h2 className="flex items-center gap-3 mb-4 text-3xl font-bold text-white">
<FolderKanban className="text-orange-500" />
پروژههای منتخب
</h2>
<p className="text-gray-400">گزیدهای از چالشهایی که با موفقیت پشت سر گذاشتیم.</p>
</div>
{/* Tabs */}
<div className="flex flex-wrap items-center gap-2 p-1 border bg-slate-900/50 rounded-xl border-slate-800 w-fit">
{tabs.map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
activeTab === tab ? "bg-orange-500 text-white shadow-lg shadow-orange-500/20" : "text-gray-400 hover:text-white hover:bg-slate-800/50"
}`}
>
{tab}
</button>
))}
</div>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{filteredProjects.map((project) => (
<div
key={project.id}
className="overflow-hidden transition-all duration-300 border cursor-pointer group bg-slate-900/30 border-slate-800 rounded-2xl hover:border-orange-500/50"
>
{/* Image placeholder */}
<div className={`h-48 w-full ${project.image} relative overflow-hidden`}>
<div className="absolute inset-0 bg-gradient-to-t from-slate-900 via-transparent to-transparent opacity-80"></div>
<div className="absolute px-3 py-1 text-xs text-gray-300 border rounded-full top-4 right-4 bg-black/50 backdrop-blur-sm border-slate-700">
{project.category}
</div>
</div>
<div className="p-6">
<h3 className="mb-2 text-xl font-bold text-white transition-colors group-hover:text-orange-500">{project.title}</h3>
<p className="mb-6 text-sm text-gray-400 line-clamp-2">{project.description}</p>
<div className="flex items-center justify-between text-sm font-medium text-orange-500">
<span>مشاهده پروژه</span>
<ArrowUpLeft className="w-5 h-5 transition-transform group-hover:-translate-y-1 group-hover:translate-x-1" />
</div>
</div>
</div>
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,89 @@
"use client";
import { useState } from "react";
import { ArrowUpLeft, ArrowUpRight, FolderKanban } from "lucide-react";
import { Portfolio } from "@/utilities/types/portfolio.type";
import { useTranslations, useLocale } from "next-intl";
import Image from "next/image";
import { BACKEND_URL } from "@/utilities/constants/urls.constant";
const tabs = ["all", "software", "network"] as const;
export default function Projects({ data }: { data: Portfolio[] }) {
const [activeTab, setActiveTab] = useState<string>("all");
const t = useTranslations("home.projects");
const locale = useLocale();
const filteredPortfolios = data.filter((p) => (activeTab === "all" ? true : p.category === activeTab));
const ArrowIcon = locale === "en" ? ArrowUpRight : ArrowUpLeft;
return (
<section className="py-12 border-t border-slate-800/50" id="portfolios_form">
<div className="flex flex-col justify-between gap-6 mb-12 md:flex-row md:items-end">
<div>
<h2 className="flex items-center gap-3 mb-4 text-3xl font-bold text-white">
<FolderKanban className="text-orange-500" />
{t("title")}
</h2>
<p className="text-gray-400">{t("subtitle")}</p>
</div>
{/* Tabs */}
<div className="flex flex-wrap items-center gap-2 p-1 border bg-slate-900/50 rounded-xl border-slate-800 w-fit">
{tabs.map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
activeTab === tab ? "bg-orange-500 text-white shadow-lg shadow-orange-500/20" : "text-gray-400 hover:text-white hover:bg-slate-800/50"
}`}
>
{t(`tabs.${tab}`)}
</button>
))}
</div>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{filteredPortfolios.map((p) => (
<div
key={p.id}
className="flex flex-col h-full overflow-hidden transition-all duration-300 border cursor-pointer group bg-slate-900/30 border-slate-800 rounded-2xl hover:border-orange-500/50"
>
{/* Image placeholder */}
<div className="relative w-full h-48 overflow-hidden shrink-0">
<Image
src={`${BACKEND_URL}/uploads/${p.featuredImage}`}
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover transition-transform duration-500 group-hover:scale-105"
alt={`تصویر ${p.title}`}
/>
<div className="absolute px-3 py-1 text-xs text-gray-300 border rounded-full top-4 right-4 rtl:right-auto rtl:left-4 bg-black/50 backdrop-blur-sm border-slate-700">
{t(`tabs.${p.category}`)}
</div>
</div>
{/* Content wrapper taking remaining height */}
<div className="flex flex-col flex-1 p-6">
{/* Title & Desc wrapper pushed to top */}
<div className="mb-auto">
<h3 className="mb-2 text-xl font-bold text-white transition-colors group-hover:text-orange-500 line-clamp-2">{p.title}</h3>
<p className="mb-6 text-sm text-gray-400 line-clamp-2">{p.description}</p>
</div>
{/* View Project button pushed to bottom */}
<div className="flex items-center justify-between mt-4 text-sm font-medium text-orange-500">
<span>{t("view_project")}</span>
<ArrowIcon
className={`w-5 h-5 transition-transform group-hover:-translate-y-1 ${locale === "en" ? "group-hover:translate-x-1" : "group-hover:-translate-x-1"}`}
/>
</div>
</div>
</div>
))}
</div>
</section>
);
}

View File

@@ -1,12 +1,16 @@
import React from "react"; import React from "react";
import { Network, Code, PenTool, GraduationCap } from "lucide-react"; import { Network, Code, PenTool, GraduationCap } from "lucide-react";
import { useTranslations } from "next-intl";
import Link from "next/link";
export default function Services() {
const t = useTranslations("home.services");
export default function BentoServices() {
return ( return (
<section> <section>
<div className="mb-12 text-center"> <div className="mb-12 text-center">
<h2 className="mb-4 text-3xl font-bold text-white">راهکارهای یکپارچه</h2> <h2 className="mb-4 text-3xl font-bold text-white">{t("title")}</h2>
<p className="text-gray-400">خدمات ما پازلهای تکمیلکننده کسبوکار شما هستند.</p> <p className="text-gray-400">{t("subtitle")}</p>
</div> </div>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2"> <div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
@@ -17,11 +21,9 @@ export default function BentoServices() {
<div className="p-3 text-orange-500 bg-slate-800 rounded-xl"> <div className="p-3 text-orange-500 bg-slate-800 rounded-xl">
<Network className="w-6 h-6" /> <Network className="w-6 h-6" />
</div> </div>
<h3 className="text-2xl font-bold">زیرساخت و امنیت شبکه</h3> <h3 className="text-2xl font-bold">{t("network.title")}</h3>
</div> </div>
<p className="max-w-md leading-relaxed text-gray-400"> <p className="max-w-md leading-relaxed text-gray-400">{t("network.desc")}</p>
طراحی، پیادهسازی و ایمنسازی شبکههای پیچیده. از کانفیگ روترهای سختافزاری تا مانیتورینگ لایه هفت.
</p>
</div> </div>
<div className="relative w-full h-32 mt-8 overflow-hidden border bg-slate-800/50 rounded-xl border-slate-700/50"> <div className="relative w-full h-32 mt-8 overflow-hidden border bg-slate-800/50 rounded-xl border-slate-700/50">
{/* Decorative element representing network */} {/* Decorative element representing network */}
@@ -40,9 +42,9 @@ export default function BentoServices() {
<div className="p-2 text-orange-500 rounded-lg bg-slate-800"> <div className="p-2 text-orange-500 rounded-lg bg-slate-800">
<Code className="w-5 h-5" /> <Code className="w-5 h-5" />
</div> </div>
<h3 className="text-xl font-bold">توسعه نرمافزار اختصاصی</h3> <h3 className="text-xl font-bold">{t("software.title")}</h3>
</div> </div>
<p className="text-sm text-gray-400">ساخت پلتفرمهای ابری قدرتمند و اتوماسیون فرآیندهای سازمانی.</p> <p className="text-sm text-gray-400">{t("software.desc")}</p>
</div> </div>
{/* Bottom Two Cards */} {/* Bottom Two Cards */}
@@ -51,19 +53,22 @@ export default function BentoServices() {
<div className="flex flex-col justify-between p-6 transition-colors border bg-slate-900/40 border-slate-800 rounded-2xl hover:border-orange-500/50"> <div className="flex flex-col justify-between p-6 transition-colors border bg-slate-900/40 border-slate-800 rounded-2xl hover:border-orange-500/50">
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2">
<PenTool className="w-5 h-5 text-orange-500" /> <PenTool className="w-5 h-5 text-orange-500" />
<h3 className="text-lg font-bold">هویت بصری</h3> <h3 className="text-lg font-bold">{t("branding.title")}</h3>
</div> </div>
<p className="mt-2 text-xs text-gray-400">طراحی رابط کاربری (UI/UX) و برندینگ مدرن.</p> <p className="mt-2 text-xs text-gray-400">{t("branding.desc")}</p>
</div> </div>
{/* Academy Card */} {/* Academy Card */}
<div className="relative flex flex-col items-center justify-center p-6 overflow-hidden text-center transition-colors border bg-gradient-to-br from-slate-900 to-slate-800 border-slate-700 rounded-2xl hover:border-orange-500/50"> <div className="relative flex flex-col items-center justify-center p-6 overflow-hidden text-center transition-colors border bg-gradient-to-br from-slate-900 to-slate-800 border-slate-700 rounded-2xl hover:border-orange-500/50">
<div className="absolute inset-0 bg-orange-500/5"></div> <div className="absolute inset-0 bg-orange-500/5"></div>
<GraduationCap className="relative z-10 w-8 h-8 mb-3 text-orange-500" /> <GraduationCap className="relative z-10 w-8 h-8 mb-3 text-orange-500" />
<h3 className="relative z-10 mb-3 text-lg font-bold">آکادمی</h3> <h3 className="relative z-10 mb-3 text-lg font-bold">{t("academy.title")}</h3>
<button className="relative z-10 px-6 py-2 text-sm text-white transition-colors border rounded-lg bg-slate-800 hover:bg-slate-700 border-slate-600"> <Link
ورود href={"/academy"}
</button> className="relative z-10 px-6 py-2 text-sm text-white transition-colors border rounded-lg bg-slate-800 hover:bg-slate-700 border-slate-600"
>
{t("academy.btn_enter")}
</Link>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,35 @@
import { useTranslations } from "next-intl";
import HeroButtons from "./HeroButtons";
import HeroTech from "./HeroTech";
export default function Hero() {
const t = useTranslations("home.hero");
return (
<>
<section className="flex flex-col items-center justify-center max-w-4xl px-4 mx-auto text-center">
{/* Top Badge */}
<div className="inline-flex items-center gap-2 px-4 py-2 mb-8 text-sm text-orange-400 border rounded-full border-orange-500/20 bg-orange-500/10">
<span className="w-2 h-2 bg-orange-500 rounded-full animate-pulse"></span>
{t("badge")}
</div>
{/* Main Title */}
<h1 className="mb-6 text-5xl font-bold leading-tight md:text-7xl">
{t("title1")}
<br />
{t("title2")}
</h1>
{/* Subtitle */}
<p className="max-w-2xl mb-10 text-lg leading-relaxed text-gray-400 md:text-xl">{t("subtitle")}</p>
{/* CTA Buttons */}
<div className="flex flex-col items-center gap-4 sm:flex-row">
<HeroButtons />
</div>
</section>
<HeroTech />
</>
);
}

View File

@@ -0,0 +1,31 @@
"use client";
import { handleScrollToId } from "@/utilities/lib/scroll";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useTranslations, useLocale } from "next-intl";
export default function HeroButtons() {
const t = useTranslations("home.hero");
const locale = useLocale();
// Choose the right chevron based on text direction
const isRtl = locale === "fa" || locale === "ar";
return (
<>
<button
onClick={() => handleScrollToId("portfolios_form")}
className="flex items-center justify-center w-full px-8 py-3 font-medium text-white transition-colors border rounded-lg sm:w-auto border-slate-700 bg-slate-800/50 hover:bg-slate-800"
>
{t("btn_portfolio")}
</button>
<button
onClick={() => handleScrollToId("contact_form")}
className="flex items-center justify-center w-full gap-2 px-8 py-3 font-medium text-white transition-colors bg-orange-600 rounded-lg sm:w-auto hover:bg-orange-500"
>
{t("btn_consulting")}
{isRtl ? <ChevronLeft className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />}
</button>
</>
);
}

View File

@@ -1,14 +1,12 @@
export default function TechMarquee() { export default function HeroTech() {
const techs = ["Node.js", "Next.js", "MikroTik", "Figma", "Ollama AI", "Docker & Coolify", ".NET"]; const techs = ["Node.js", "Next.js", "MikroTik", "Figma", "Ollama AI", "Docker & Coolify", ".NET"];
return ( return (
<div className="relative w-full py-4 overflow-hidden border-y border-slate-800/50 bg-slate-900/20"> <div className="relative w-full py-4 overflow-hidden border-y border-slate-800/50 bg-slate-900/20">
{/* Gradient masks for fading edges */}
<div className="absolute inset-y-0 right-0 w-32 bg-gradient-to-l from-[#0B1120] to-transparent z-10"></div> <div className="absolute inset-y-0 right-0 w-32 bg-gradient-to-l from-[#0B1120] to-transparent z-10"></div>
<div className="absolute inset-y-0 left-0 w-32 bg-gradient-to-r from-[#0B1120] to-transparent z-10"></div> <div className="absolute inset-y-0 left-0 w-32 bg-gradient-to-r from-[#0B1120] to-transparent z-10"></div>
<div className="flex flex-wrap justify-center gap-12 px-4 opacity-50 whitespace-nowrap"> <div className="flex flex-wrap justify-center gap-12 px-4 opacity-50 whitespace-nowrap">
{/* In a real app, you'd use a CSS animation here for infinite scrolling */}
{techs.map((tech, index) => ( {techs.map((tech, index) => (
<div key={index} className="flex items-center gap-2 text-lg font-medium text-gray-400"> <div key={index} className="flex items-center gap-2 text-lg font-medium text-gray-400">
<span className="flex items-center justify-center w-6 h-6 text-xs border rounded bg-slate-800 border-slate-700"></span> <span className="flex items-center justify-center w-6 h-6 text-xs border rounded bg-slate-800 border-slate-700"></span>

View File

@@ -1,6 +1,6 @@
export default function Consultation() { export default function Consultation() {
return ( return (
<div className="w-full max-w-6xl px-5 mx-auto mt-10"> <div className="w-full max-w-6xl px-5 mx-auto mt-10" id="contact_form">
<div className="relative grid grid-cols-1 gap-10 p-10 overflow-hidden border border-b-0 shadow-2xl bg-panel border-border rounded-t-3xl lg:grid-cols-2"> <div className="relative grid grid-cols-1 gap-10 p-10 overflow-hidden border border-b-0 shadow-2xl bg-panel border-border rounded-t-3xl lg:grid-cols-2">
<div className="absolute -top-12 left-1/2 -translate-x-1/2 w-[80%] h-[100px] bg-[radial-gradient(ellipse,rgba(199,92,67,0.15),transparent_70%)] pointer-events-none" /> <div className="absolute -top-12 left-1/2 -translate-x-1/2 w-[80%] h-[100px] bg-[radial-gradient(ellipse,rgba(199,92,67,0.15),transparent_70%)] pointer-events-none" />

View File

@@ -1,34 +1,78 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import Link from "next/link";
import { useTranslations, useLocale } from "next-intl";
import { usePathname, useRouter } from "next/navigation";
export default function Navbar() { export default function Navbar() {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const t = useTranslations("navbar");
const locale = useLocale();
const pathname = usePathname();
const router = useRouter();
const languages = [
{ code: "fa", flag: "🇮🇷", label: "فارسی" },
{ code: "en", flag: "🇬🇧", label: "English" },
{ code: "ar", flag: "🇸🇦", label: "العربية" },
];
const handleLanguageChange = (newLocale: string) => {
// Replace the current locale in the URL path with the new one
const newPath = pathname.replace(new RegExp(`^/${locale}`), `/${newLocale}`);
router.replace(newPath);
};
return ( return (
<header className="sticky top-0 z-50 border-b backdrop-blur-lg bg-bg/80 border-white/5"> <header className="sticky top-0 z-50 border-b backdrop-blur-lg bg-bg/80 border-white/5">
<div className="flex items-center justify-between px-6 py-4 mx-auto max-w-7xl"> <div className="flex items-center justify-between px-6 py-4 mx-auto max-w-7xl">
{/* Logo */} {/* Logo */}
<div className="text-xl font-bold"> <Link href={`/${locale}`} className="text-xl font-bold">
رابین <span className="text-accent">شبکه</span> {t("logo1")} <span className="text-accent">{t("logo2")}</span>
</div> </Link>
{/* Desktop Navigation */} {/* Desktop Navigation */}
<nav className="hidden md:block"> <nav className="hidden md:block">
<ul className="flex gap-8 text-sm text-muted"> <ul className="flex gap-8 text-sm text-muted">
<li className="transition cursor-pointer hover:text-foreground">صفحه اصلی</li> <li>
<li className="transition cursor-pointer hover:text-foreground">خدمات</li> <Link href={`/${locale}`} className="transition cursor-pointer hover:text-foreground">
<li className="transition cursor-pointer hover:text-foreground">تکنولوژی</li> {t("home")}
<li className="transition cursor-pointer hover:text-foreground">فرآیند</li> </Link>
<li className="transition cursor-pointer hover:text-foreground">پروژهها</li> </li>
<li>
<Link href={`/${locale}/software`} className="transition cursor-pointer hover:text-foreground">
{t("software")}
</Link>
</li>
<li>
<Link href={`/${locale}/network`} className="transition cursor-pointer hover:text-foreground">
{t("network")}
</Link>
</li>
<li>
<Link href={`/${locale}/academy`} className="transition cursor-pointer hover:text-foreground">
{t("academy")}
</Link>
</li>
</ul> </ul>
</nav> </nav>
{/* Desktop Actions & Mobile Menu Toggle */} {/* Desktop Actions & Mobile Menu Toggle */}
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="hidden gap-3 md:flex"> <div className="hidden gap-2 md:flex">
<button className="border border-border px-3 py-1.5 rounded-md text-sm hover:bg-card transition">EN</button> {languages.map((language) => (
<button className="border border-border px-3 py-1.5 rounded-md text-sm hover:bg-card transition"></button> <button
key={language.code}
onClick={() => handleLanguageChange(language.code)}
className={`border px-3 py-1.5 rounded-md text-sm transition ${
locale === language.code ? "border-accent bg-accent/10" : "border-border hover:bg-card"
}`}
title={language.label}
>
{language.flag}
</button>
))}
</div> </div>
{/* Mobile Menu Button */} {/* Mobile Menu Button */}
@@ -51,17 +95,41 @@ export default function Navbar() {
<div className="border-t md:hidden border-white/5 bg-bg/95 backdrop-blur-lg"> <div className="border-t md:hidden border-white/5 bg-bg/95 backdrop-blur-lg">
<nav className="px-6 py-4"> <nav className="px-6 py-4">
<ul className="flex flex-col gap-4 text-sm text-muted"> <ul className="flex flex-col gap-4 text-sm text-muted">
<li className="transition cursor-pointer hover:text-foreground">صفحه اصلی</li> <li>
<li className="transition cursor-pointer hover:text-foreground">خدمات</li> <Link href={`/${locale}`} className="transition cursor-pointer hover:text-foreground" onClick={() => setIsOpen(false)}>
<li className="transition cursor-pointer hover:text-foreground">تکنولوژی</li> {t("home")}
<li className="transition cursor-pointer hover:text-foreground">فرآیند</li> </Link>
<li className="transition cursor-pointer hover:text-foreground">پروژهها</li> </li>
<li>
<Link href={`/${locale}/software`} className="transition cursor-pointer hover:text-foreground" onClick={() => setIsOpen(false)}>
{t("software")}
</Link>
</li>
<li>
<Link href={`/${locale}/network`} className="transition cursor-pointer hover:text-foreground" onClick={() => setIsOpen(false)}>
{t("network")}
</Link>
</li>
<li>
<Link href={`/${locale}/academy`} className="transition cursor-pointer hover:text-foreground" onClick={() => setIsOpen(false)}>
{t("academy")}
</Link>
</li>
</ul> </ul>
{/* Mobile Actions */} {/* Mobile Language Switcher */}
<div className="flex gap-3 pt-4 mt-6 border-t border-white/5"> <div className="flex gap-2 pt-4 mt-6 border-t border-white/5">
<button className="border border-border px-3 py-1.5 rounded-md text-sm hover:bg-card transition flex-1">EN</button> {languages.map((language) => (
<button className="border border-border px-3 py-1.5 rounded-md text-sm hover:bg-card transition flex-1"></button> <button
key={language.code}
onClick={() => handleLanguageChange(language.code)}
className={`border px-3 py-1.5 rounded-md text-sm transition flex-1 ${
locale === language.code ? "border-accent bg-accent/10" : "border-border hover:bg-card"
}`}
>
{language.flag} {language.label}
</button>
))}
</div> </div>
</nav> </nav>
</div> </div>

18
src/i18n.ts Normal file
View File

@@ -0,0 +1,18 @@
// src/i18n.ts
import { getRequestConfig } from "next-intl/server";
import { notFound } from "next/navigation";
const locales = ["fa", "en", "ar"];
export default getRequestConfig(async ({ requestLocale }) => {
let locale = await requestLocale;
if (!locale || !locales.includes(locale as string)) {
locale = "fa";
}
return {
locale,
messages: (await import(`./messages/${locale}.json`)).default,
};
});

50
src/messages/ar.json Normal file
View File

@@ -0,0 +1,50 @@
{
"navbar": {
"home": "الرئيسية",
"software": "برمجة",
"network": "شبكة",
"academy": "أكاديمية",
"logo1": "رابين",
"logo2": "شبكة"
},
"home": {
"hero": {
"badge": "هندسة الأنظمة القابلة للتطوير",
"title1": "نحن نفك عقدك",
"title2": "التقنية",
"subtitle": "مزيج من السلطة الهندسية في البنية التحتية والابتكار الحديث في تطوير البرمجيات، من إعداد الشبكات المعقدة إلى تطوير منصات سحابية مخصصة.",
"btn_consulting": "احصل على استشارة مجانية",
"btn_portfolio": "عرض الأعمال"
},
"services": {
"title": "حلول متكاملة",
"subtitle": "خدماتنا هي القطع المكملة للغز عملك.",
"network": {
"title": "البنية التحتية وأمن الشبكات",
"desc": "تصميم وتنفيذ وتأمين الشبكات المعقدة. من تكوين أجهزة التوجيه إلى مراقبة الطبقة السابعة."
},
"software": {
"title": "تطوير برمجيات مخصصة",
"desc": "بناء منصات سحابية قوية وأتمتة العمليات المؤسسية."
},
"branding": {
"title": "الهوية البصرية",
"desc": "تصميم واجهة المستخدم (UI/UX) والعلامات التجارية الحديثة."
},
"academy": {
"title": "أكاديمية",
"btn_enter": "مشاهدة"
}
},
"projects": {
"title": "مشاريع مختارة",
"subtitle": "مجموعة مختارة من التحديات التي تغلبنا عليها بنجاح.",
"view_project": "عرض المشروع",
"tabs": {
"all": "الكل",
"software": "برمجيات",
"network": "شبكات"
}
}
}
}

50
src/messages/en.json Normal file
View File

@@ -0,0 +1,50 @@
{
"navbar": {
"home": "Home",
"software": "Software",
"network": "Network",
"academy": "Academy",
"logo1": "Robin",
"logo2": "Network"
},
"home": {
"hero": {
"badge": "Scalable Systems Architecture",
"title1": "We untangle your",
"title2": "technical knots",
"subtitle": "A combination of engineering authority in infrastructure and modern innovation in software development, from setting up complex networks to developing custom cloud platforms.",
"btn_consulting": "Get Free Consultation",
"btn_portfolio": "View Portfolio"
},
"services": {
"title": "Integrated Solutions",
"subtitle": "Our services are the missing pieces of your business puzzle.",
"network": {
"title": "Network Infrastructure & Security",
"desc": "Designing, implementing, and securing complex networks. From hardware router configuration to Layer 7 monitoring."
},
"software": {
"title": "Custom Software Development",
"desc": "Building powerful cloud platforms and enterprise process automation."
},
"branding": {
"title": "Visual Identity",
"desc": "Modern UI/UX design and branding."
},
"academy": {
"title": "Academy",
"btn_enter": "View"
}
},
"projects": {
"title": "Featured Projects",
"subtitle": "A selection of challenges we have successfully overcome.",
"view_project": "View Project",
"tabs": {
"all": "All",
"software": "Software",
"network": "Network"
}
}
}
}

50
src/messages/fa.json Normal file
View File

@@ -0,0 +1,50 @@
{
"navbar": {
"home": "صفحه اصلی",
"software": "نرم افزار",
"network": "شبکه",
"academy": "آکادمی",
"logo1": "رابین",
"logo2": "شبکه"
},
"home": {
"hero": {
"badge": "معماری سیستم‌های مقیاس‌پذیر",
"title1": "ما گره‌های فنی شما را",
"title2": "باز می‌کنیم",
"subtitle": "ترکیبی از اقتدار مهندسی در زیرساخت و نوآوری مدرن در توسعه نرم‌افزار، از راه‌اندازی شبکه‌های پیچیده تا توسعه پلتفرم‌های ابری سفارشی.",
"btn_consulting": "دریافت مشاوره رایگان",
"btn_portfolio": "مشاهده نمونه‌کارها"
},
"services": {
"title": "راهکارهای یکپارچه",
"subtitle": "خدمات ما پازل‌های تکمیل‌کننده کسب‌وکار شما هستند.",
"network": {
"title": "زیرساخت و امنیت شبکه",
"desc": "طراحی، پیاده‌سازی و ایمن‌سازی شبکه‌های پیچیده. از کانفیگ روترهای سخت‌افزاری تا مانیتورینگ لایه هفت."
},
"software": {
"title": "توسعه نرم‌افزار اختصاصی",
"desc": "ساخت پلتفرم‌های ابری قدرتمند و اتوماسیون فرآیندهای سازمانی."
},
"branding": {
"title": "هویت بصری",
"desc": "طراحی رابط کاربری (UI/UX) و برندینگ مدرن."
},
"academy": {
"title": "آکادمی",
"btn_enter": "مشاهده"
}
},
"projects": {
"title": "پروژه‌های منتخب",
"subtitle": "گزیده‌ای از چالش‌هایی که با موفقیت پشت سر گذاشتیم.",
"view_project": "مشاهده پروژه",
"tabs": {
"all": "همه",
"software": "نرم‌افزار",
"network": "شبکه"
}
}
}
}

12
src/middleware.ts Normal file
View File

@@ -0,0 +1,12 @@
// src/middleware.ts
import createMiddleware from "next-intl/middleware";
export default createMiddleware({
locales: ["fa", "en", "ar"],
defaultLocale: "fa",
localePrefix: "always",
});
export const config = {
matcher: ["/", "/(fa|en|ar)/:path*", "/((?!_next|_vercel|.*\\..*).*)"],
};

View File

@@ -0,0 +1,2 @@
export const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL;
export const BACKEND_URL_LOCAL = process.env.NEXT_PUBLIC_BACKEND_URL_LOCAL;

View File

@@ -0,0 +1,10 @@
export const handleScrollToId = (id: string) => {
const target = document.getElementById(id);
if (target) {
target.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
};

View File

@@ -0,0 +1,13 @@
export interface Portfolio {
id: string;
category: PortfolioCategoryType;
externalLink: string;
featuredImage: string;
gallery: string[];
href: string;
title: string;
description: string;
employer: string;
}
export type PortfolioCategoryType = "network" | "software";