diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..2125666
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto
\ No newline at end of file
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index ed782a5..7343a64 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -50,4 +50,4 @@ jobs:
- name: Start containers
run: |
- docker compose -f docker-compose.yaml up -d
\ No newline at end of file
+ docker compose -f docker-compose.yaml up -d
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 0000000..d0a7784
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+npx lint-staged
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..5f2dc64
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/webResources.xml b/.idea/webResources.xml
new file mode 100644
index 0000000..3432ba4
--- /dev/null
+++ b/.idea/webResources.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..6a12cc2
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,6 @@
+.git
+.idea
+.vscode
+.next
+/node_modules
+*.md
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..6151634
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,14 @@
+{
+ "tabWidth": 2,
+ "semi": true,
+ "printWidth": 80,
+ "trailingComma": "all",
+ "singleQuote": true,
+ "bracketSpacing": true,
+ "arrowParens": "always",
+ "bracketSameLine": false,
+ "proseWrap": "always",
+ "useTabs": false,
+ "endOfLine": "lf",
+ "jsxSingleQuote": true
+}
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 9ac6fd0..a5c6f10 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -6,5 +6,4 @@ services:
container_name: fire-exam
restart: unless-stopped
ports:
- - "5002:3000"
-
+ - '5002:3000'
diff --git a/eslint.config.mjs b/eslint.config.mjs
index c85fb67..7f86eca 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,6 +1,6 @@
-import { dirname } from "path";
-import { fileURLToPath } from "url";
-import { FlatCompat } from "@eslint/eslintrc";
+import { dirname } from 'path';
+import { fileURLToPath } from 'url';
+import { FlatCompat } from '@eslint/eslintrc';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
@@ -10,7 +10,7 @@ const compat = new FlatCompat({
});
const eslintConfig = [
- ...compat.extends("next/core-web-vitals", "next/typescript"),
+ ...compat.extends('next/core-web-vitals', 'next/typescript'),
];
export default eslintConfig;
diff --git a/next.config.ts b/next.config.ts
index 55238ac..1f7ea33 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,8 +1,17 @@
-import type { NextConfig } from "next";
+import type { NextConfig } from 'next';
+import path from 'path';
const nextConfig: NextConfig = {
/* config options here */
output: 'standalone',
+ sassOptions: {
+ includePaths: [path.resolve('./src/core/styles')],
+ prependData: `@import "index.scss";`,
+ },
+ compiler: {
+ removeConsole:
+ process.env.NODE_ENV === 'production' ? { exclude: ['error'] } : false,
+ },
};
export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index fcdbef0..fb3554a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,8 +17,13 @@
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
+ "clsx": "^2.1.1",
"eslint": "^9",
"eslint-config-next": "15.3.2",
+ "husky": "^9.1.7",
+ "lint-staged": "^16.1.0",
+ "prettier": "3.5.3",
+ "sass": "1.77.8",
"typescript": "^5"
}
},
@@ -1481,6 +1486,35 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ansi-escapes": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
+ "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "environment": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -1497,6 +1531,20 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1732,6 +1780,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1747,7 +1808,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@@ -1864,12 +1925,93 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-truncate": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
+ "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "slice-ansi": "^5.0.0",
+ "string-width": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@@ -1915,6 +2057,23 @@
"simple-swizzle": "^0.2.2"
}
},
+ "node_modules/colorette": {
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz",
+ "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2111,6 +2270,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/environment": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
+ "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.23.10",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz",
@@ -2724,6 +2896,13 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2802,7 +2981,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -2865,6 +3044,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -2906,6 +3100,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -3133,6 +3340,22 @@
"node": ">= 0.4"
}
},
+ "node_modules/husky": {
+ "version": "9.1.7",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
+ "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "husky": "bin.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/typicode"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3143,6 +3366,13 @@
"node": ">= 4"
}
},
+ "node_modules/immutable": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
+ "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -3246,6 +3476,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-boolean-object": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
@@ -3341,7 +3584,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -3363,6 +3606,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-fullwidth-code-point": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
+ "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-generator-function": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
@@ -3386,7 +3642,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -3412,7 +3668,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -3726,6 +3982,78 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/lint-staged": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.0.tgz",
+ "integrity": "sha512-HkpQh69XHxgCjObjejBT3s2ILwNjFx8M3nw+tJ/ssBauDlIpkx2RpqWSi1fBgkXLSSXnbR3iEq1NkVtpvV+FLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.4.1",
+ "commander": "^14.0.0",
+ "debug": "^4.4.1",
+ "lilconfig": "^3.1.3",
+ "listr2": "^8.3.3",
+ "micromatch": "^4.0.8",
+ "nano-spawn": "^1.0.2",
+ "pidtree": "^0.6.0",
+ "string-argv": "^0.3.2",
+ "yaml": "^2.8.0"
+ },
+ "bin": {
+ "lint-staged": "bin/lint-staged.js"
+ },
+ "engines": {
+ "node": ">=20.17"
+ },
+ "funding": {
+ "url": "https://opencollective.com/lint-staged"
+ }
+ },
+ "node_modules/lint-staged/node_modules/chalk": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
+ "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/listr2": {
+ "version": "8.3.3",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz",
+ "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cli-truncate": "^4.0.0",
+ "colorette": "^2.0.20",
+ "eventemitter3": "^5.0.1",
+ "log-update": "^6.1.0",
+ "rfdc": "^1.4.1",
+ "wrap-ansi": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -3749,6 +4077,72 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/log-update": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
+ "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-escapes": "^7.0.0",
+ "cli-cursor": "^5.0.0",
+ "slice-ansi": "^7.1.0",
+ "strip-ansi": "^7.1.0",
+ "wrap-ansi": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/is-fullwidth-code-point": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
+ "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-east-asian-width": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/slice-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
+ "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.2.1",
+ "is-fullwidth-code-point": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -3796,6 +4190,19 @@
"node": ">=8.6"
}
},
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -3826,6 +4233,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/nano-spawn": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.2.tgz",
+ "integrity": "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.17"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
@@ -3921,6 +4341,16 @@
}
}
},
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -4044,6 +4474,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -4162,7 +4608,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -4171,6 +4617,19 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pidtree": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
+ "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "pidtree": "bin/pidtree.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -4219,6 +4678,22 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -4290,6 +4765,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -4375,6 +4863,23 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
+ "node_modules/restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -4386,6 +4891,13 @@
"node": ">=0.10.0"
}
},
+ "node_modules/rfdc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -4465,6 +4977,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/sass": {
+ "version": "1.77.8",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz",
+ "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/scheduler": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
@@ -4674,6 +5204,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@@ -4684,6 +5227,36 @@
"is-arrayish": "^0.3.1"
}
},
+ "node_modules/slice-ansi": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
+ "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.0.0",
+ "is-fullwidth-code-point": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -4708,6 +5281,41 @@
"node": ">=10.0.0"
}
},
+ "node_modules/string-argv": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.19"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width/node_modules/emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/string.prototype.includes": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
@@ -4821,6 +5429,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
@@ -4942,7 +5566,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@@ -5272,6 +5896,50 @@
"node": ">=0.10.0"
}
},
+ "node_modules/wrap-ansi": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
+ "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.2.1",
+ "string-width": "^7.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/yaml": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
+ "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index 1c2eea2..5e15dfb 100644
--- a/package.json
+++ b/package.json
@@ -6,20 +6,33 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
- "lint": "next lint"
+ "lint": "next lint",
+ "prettier": "prettier --write .",
+ "prepare": "husky"
},
"dependencies": {
+ "next": "15.3.2",
"react": "^19.0.0",
- "react-dom": "^19.0.0",
- "next": "15.3.2"
+ "react-dom": "^19.0.0"
},
"devDependencies": {
- "typescript": "^5",
+ "@eslint/eslintrc": "^3",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
+ "clsx": "^2.1.1",
"eslint": "^9",
"eslint-config-next": "15.3.2",
- "@eslint/eslintrc": "^3"
+ "husky": "^9.1.7",
+ "lint-staged": "^16.1.0",
+ "prettier": "3.5.3",
+ "sass": "1.77.8",
+ "typescript": "^5"
+ },
+ "lint-staged": {
+ "*.{js,jsx,ts,tsx}": [
+ "eslint --fix",
+ "prettier --write"
+ ]
}
}
diff --git a/public/file.svg b/public/file.svg
deleted file mode 100644
index 004145c..0000000
--- a/public/file.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/globe.svg b/public/globe.svg
deleted file mode 100644
index 567f17b..0000000
--- a/public/globe.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/images/bg-start-desktop.jpg b/public/images/bg-start-desktop.jpg
new file mode 100644
index 0000000..dae1c98
Binary files /dev/null and b/public/images/bg-start-desktop.jpg differ
diff --git a/public/next.svg b/public/next.svg
deleted file mode 100644
index 5174b28..0000000
--- a/public/next.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/svg/phone-calling.svg b/public/svg/phone-calling.svg
new file mode 100644
index 0000000..0d89577
--- /dev/null
+++ b/public/svg/phone-calling.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/svg/telegram.svg b/public/svg/telegram.svg
new file mode 100644
index 0000000..5155ff9
--- /dev/null
+++ b/public/svg/telegram.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/svg/whatsapp.svg b/public/svg/whatsapp.svg
new file mode 100644
index 0000000..cebd190
--- /dev/null
+++ b/public/svg/whatsapp.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/vercel.svg b/public/vercel.svg
deleted file mode 100644
index 7705396..0000000
--- a/public/vercel.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/window.svg b/public/window.svg
deleted file mode 100644
index b2b2a44..0000000
--- a/public/window.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 922ab97..def1610 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,32 +1,38 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
-import "./globals.css";
+import type { Metadata } from 'next';
+import { Open_Sans } from 'next/font/google';
+import '@core/styles/reset.scss';
+import '@core/styles/globals.scss';
-const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
+const openSans = Open_Sans({
+ subsets: ['latin', 'cyrillic'],
+ weight: ['300', '400', '500', '600', '700'],
+ variable: '--open-sans',
});
export const metadata: Metadata = {
- title: "Пожарная экспертиза",
- description: "Пожарная экспертиза",
+ title: 'Обследование на соответствие пожарной безопасности',
+ description:
+ 'Полное обследование объекта на соответствие требованиям пожарной безопасности',
+ openGraph: {
+ title: 'Обследование на соответствие пожарной безопасности',
+ description:
+ 'Полное обследование объекта на соответствие требованиям пожарной безопасности',
+ siteName: 'Обследование на соответствие пожарной безопасности',
+ // images: [
+ // {
+ // url: `MetaSR.png`,
+ // alt: 'icon',
+ // },
+ // ],
+ },
};
export default function RootLayout({
children,
-}: Readonly<{
- children: React.ReactNode;
-}>) {
+}: Readonly<{ children: React.ReactNode }>) {
return (
-
-
- {children}
-
+
+ {children}
);
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 4ea9ac7..c1a248a 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,4 +1,4 @@
-import HomePage from "@pages/home";
+import { HomePage } from '@pages/home';
export default function Home() {
return (
diff --git a/src/shared/.gitkeep b/src/core/constants/.gitkeep
similarity index 100%
rename from src/shared/.gitkeep
rename to src/core/constants/.gitkeep
diff --git a/src/core/styles/functions.scss b/src/core/styles/functions.scss
new file mode 100644
index 0000000..26695ad
--- /dev/null
+++ b/src/core/styles/functions.scss
@@ -0,0 +1,6 @@
+@use 'sass:math';
+
+@function rem($size) {
+ $remSize: math.div($size, $base-font-size);
+ @return $remSize * 1rem;
+}
\ No newline at end of file
diff --git a/src/app/globals.css b/src/core/styles/globals.scss
similarity index 65%
rename from src/app/globals.css
rename to src/core/styles/globals.scss
index e3734be..a252305 100644
--- a/src/app/globals.css
+++ b/src/core/styles/globals.scss
@@ -1,13 +1,6 @@
:root {
--background: #ffffff;
- --foreground: #171717;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
- }
+ --foreground: #333333;
}
html,
@@ -34,9 +27,3 @@ a {
color: inherit;
text-decoration: none;
}
-
-@media (prefers-color-scheme: dark) {
- html {
- color-scheme: dark;
- }
-}
diff --git a/src/core/styles/index.scss b/src/core/styles/index.scss
new file mode 100644
index 0000000..e682ecd
--- /dev/null
+++ b/src/core/styles/index.scss
@@ -0,0 +1,2 @@
+@import './variables.scss';
+@import './mixins.scss';
\ No newline at end of file
diff --git a/src/core/styles/mixins.scss b/src/core/styles/mixins.scss
new file mode 100644
index 0000000..ebe01bb
--- /dev/null
+++ b/src/core/styles/mixins.scss
@@ -0,0 +1,23 @@
+@mixin onlymobile {
+ @media (min-width: 0px) and (max-width: calc($tablet - 1px)) {
+ @content;
+ }
+}
+
+@mixin iftablet {
+ @media (min-width: $tablet) {
+ @content;
+ }
+}
+
+@mixin iflaptop {
+ @media (min-width: $laptop) {
+ @content;
+ }
+}
+
+@mixin ifdesktop {
+ @media (min-width: $desktop) {
+ @content;
+ }
+}
diff --git a/src/core/styles/reset.scss b/src/core/styles/reset.scss
new file mode 100644
index 0000000..0fa9db3
--- /dev/null
+++ b/src/core/styles/reset.scss
@@ -0,0 +1,106 @@
+/* Reset and base styles */
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0); // stop highlights element blue when tapping
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+/* Links */
+
+a,
+a:link,
+a:visited {
+ text-decoration: none;
+ color: unset;
+}
+
+a:hover {
+ text-decoration: none;
+}
+
+/* Components */
+
+aside,
+nav,
+footer,
+header,
+section,
+main {
+ display: block;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p {
+ font-size: inherit;
+ font-weight: inherit;
+ margin: 0;
+ padding: 0;
+ //margin-block-start: 0;
+ //margin-block-end: 0;
+}
+
+ul[role='list'], ol[role='list'] {
+ list-style: none;
+}
+
+ul,
+ul li {
+ list-style: none;
+}
+
+/* Form */
+
+input,
+textarea,
+button,
+select {
+ font-family: inherit;
+ font-size: inherit;
+ color: inherit;
+ background-color: transparent;
+}
+
+input::-ms-clear {
+ display: none;
+}
+
+button,
+input[type='submit'] {
+ display: inline-block;
+ box-shadow: none;
+ background-color: transparent;
+ background: none;
+}
+
+input:focus,
+input:active,
+button:focus,
+button:active {
+ outline: none;
+}
+
+button::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+legend {
+ display: block;
+}
+
+img, picture, svg, video, canvas {
+ background-repeat: no-repeat;
+ background-size: cover;
+}
diff --git a/src/core/styles/variables.scss b/src/core/styles/variables.scss
new file mode 100644
index 0000000..c583629
--- /dev/null
+++ b/src/core/styles/variables.scss
@@ -0,0 +1,21 @@
+
+//frontend breakpoint
+$mobile: 360px;
+$tablet: 768px;
+$laptop: 1024px;
+$desktop: 1440px;
+
+//fonts
+$font-open-sans: var(--open-sans), sans-serif;
+
+$font-regular: 500;
+$font-semi-bold: 600;
+
+// colors
+$color-white: #FFFFFF;
+$color-black: #000000;
+$color-orange: #E96526;
+$color-lightgray: #E4E1E1;
+$color-text: #333333;
+$color-text-light: #222222;
+$color-mark: #E96526;
\ No newline at end of file
diff --git a/src/pages/home/home.module.scss b/src/pages/home/home.module.scss
new file mode 100644
index 0000000..c07779c
--- /dev/null
+++ b/src/pages/home/home.module.scss
@@ -0,0 +1,106 @@
+.Start {
+ padding: 0px 160px 0px;
+
+ &_BgWrapper {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 900px;
+ z-index: -1;
+
+ & img {
+ object-fit: cover;
+ filter: brightness(0.5);
+ }
+ }
+}
+
+.Header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid $color-white;
+ height: 80px;
+
+ .Logo {
+ color: $color-white;
+ }
+
+ .Buttons {
+ color: $color-white;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 30px;
+
+ .Icon {
+ width: 60px;
+ height: 60px;
+ cursor: pointer;
+ }
+
+ .Button {
+ display: flex;
+ flex-direction: row;
+ gap: 16px;
+ height: 48px;
+ padding: 24px;
+ }
+ }
+}
+
+.Info {
+ display: flex;
+ flex-direction: row;
+ padding: 160px 0 200px;
+
+ .Content {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ gap: 60px;
+
+ .Title {
+ font-family: $font-open-sans;
+ font-weight: $font-regular;
+ font-size: 60px;
+ line-height: 1;
+ color: $color-white;
+ max-width: 960px;
+ }
+
+ .List {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ gap: 16px;
+ }
+
+ .ListItem {
+ font-family: $font-open-sans;
+ font-weight: $font-semi-bold;
+ font-size: 26px;
+ line-height: 1;
+ color: $color-white;
+ }
+ }
+
+ .Phone {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ flex-basis: 40%;
+ gap: 40px;
+
+ .Title {
+ font-family: $font-open-sans;
+ font-weight: $font-semi-bold;
+ font-size: 60px;
+ line-height: 1;
+ color: $color-white;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/home/home.tsx b/src/pages/home/home.tsx
new file mode 100644
index 0000000..19a513c
--- /dev/null
+++ b/src/pages/home/home.tsx
@@ -0,0 +1,57 @@
+import s from './home.module.scss';
+import { Button } from '@shared/ui';
+import waIcon from '@public/svg/whatsapp.svg';
+import tgIcon from '@public/svg/telegram.svg';
+import callBtn from '@public/svg/phone-calling.svg';
+import bgStart from '@public/images/bg-start-desktop.jpg';
+import Image from 'next/image';
+
+export default function Home() {
+ return (
+
+
+
+
+
+
Пожарная экспертиза
+
+
+
+
+
+
+
+
+
+ Полное обследование объекта на соответствие требованиям пожарной
+ безопасности
+
+
+ -
+ Пожарно-техническое обследование (пожарный аудит)
+
+ - Расчёт пожарного риска
+ -
+ Сокращение затрат на модернизацию пожарных систем
+
+
+
+
+
+7 999 123 45 67
+
+
+
+
+ );
+}
diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx
index 0bd8dfc..77ef521 100644
--- a/src/pages/home/index.tsx
+++ b/src/pages/home/index.tsx
@@ -1 +1 @@
-export {default} from './ui/Home'
\ No newline at end of file
+export { default as HomePage } from './home';
diff --git a/src/pages/home/ui/Home.module.scss b/src/pages/home/ui/Home.module.scss
deleted file mode 100644
index e69de29..0000000
diff --git a/src/pages/home/ui/Home.tsx b/src/pages/home/ui/Home.tsx
deleted file mode 100644
index 3423aae..0000000
--- a/src/pages/home/ui/Home.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-function Home() {
- return (
-
- Home
-
- )
-}
-
-export default Home;
\ No newline at end of file
diff --git a/src/shared/ui/button/button.module.scss b/src/shared/ui/button/button.module.scss
new file mode 100644
index 0000000..18fb351
--- /dev/null
+++ b/src/shared/ui/button/button.module.scss
@@ -0,0 +1,46 @@
+.Button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 13px 33px;
+ border-radius: 28px;
+
+ font-family: $font-open-sans;
+ font-weight: $font-regular;
+ font-size: 24px;
+ line-height: 1;
+
+ transition: all 0.15s linear;
+ white-space: nowrap;
+
+
+ svg {
+ width: 18px;
+ height: 18px;
+ //fill: var(--text-primary);
+
+ margin-right: 18px;
+ }
+
+ &:hover {
+ cursor: pointer;
+ }
+
+ &:hover svg {
+ fill: var(--white);
+ }
+
+ &_default {
+ background: $color-lightgray;
+ color: $color-text;
+ }
+
+ &_orange {
+ background: $color-orange;
+ color: $color-white;
+ }
+
+ &_disabled {
+ cursor: not-allowed;
+ }
+}
\ No newline at end of file
diff --git a/src/shared/ui/button/button.tsx b/src/shared/ui/button/button.tsx
new file mode 100644
index 0000000..7e58bce
--- /dev/null
+++ b/src/shared/ui/button/button.tsx
@@ -0,0 +1,39 @@
+import s from './button.module.scss';
+import { FunctionComponent, HTMLAttributes, ReactNode, SVGProps } from 'react';
+import { clsx } from 'clsx';
+
+type ButtonProps = {
+ className?: string;
+ children?: ReactNode;
+ disabled?: boolean;
+ Icon?: FunctionComponent>;
+ onClick?: () => void;
+ variant?: 'default' | 'orange' | 'ghost';
+} & HTMLAttributes;
+
+export default function Button({
+ className,
+ children,
+ onClick,
+ Icon,
+ disabled,
+ variant = 'default',
+ ...props
+}: ButtonProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/ui/button/index.ts b/src/shared/ui/button/index.ts
new file mode 100644
index 0000000..31d66cb
--- /dev/null
+++ b/src/shared/ui/button/index.ts
@@ -0,0 +1 @@
+export { default as Button } from './button';
diff --git a/src/shared/ui/index.ts b/src/shared/ui/index.ts
new file mode 100644
index 0000000..a039b75
--- /dev/null
+++ b/src/shared/ui/index.ts
@@ -0,0 +1 @@
+export { Button } from './button';
diff --git a/tsconfig.json b/tsconfig.json
index 841a965..aed8a19 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,7 +23,8 @@
"@core/*": ["./src/core/*"],
"@pages/*": ["./src/pages/*"],
"@widgets/*": ["./src/widgets/*"],
- "@shared/*": ["./src/shared/*"]
+ "@shared/*": ["./src/shared/*"],
+ "@public/*": ["./public/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],