Compare commits

..

3 Commits

82 changed files with 3396 additions and 1204 deletions

198
front/package-lock.json generated
View File

@@ -28,15 +28,18 @@
"apexcharts": "3.49.2", "apexcharts": "3.49.2",
"axios": "^1.7.3", "axios": "^1.7.3",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^2.29.3",
"dayjs": "1.11.11", "dayjs": "1.11.11",
"moment": "^2.30.1", "moment": "^2.30.1",
"notistack": "^3.0.1", "notistack": "^3.0.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-apexcharts": "1.4.1", "react-apexcharts": "1.4.1",
"react-calendar": "^6.0.0",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "7.52.0", "react-hook-form": "7.52.0",
"react-jwt": "^1.2.2", "react-jwt": "^1.2.2",
"react-material-ui-carousel": "^3.4.2",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router": "^7.1.1", "react-router": "^7.1.1",
"react-router-dom": "^6.25.1", "react-router-dom": "^6.25.1",
@@ -5528,6 +5531,15 @@
"@xtuc/long": "4.2.2" "@xtuc/long": "4.2.2"
} }
}, },
"node_modules/@wojtekmaj/date-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-2.0.2.tgz",
"integrity": "sha512-Do66mSlSNifFFuo3l9gNKfRMSFi26CRuQMsDJuuKO/ekrDWuTTtE4ZQxoFCUOG+NgxnpSeBq/k5TY8ZseEzLpA==",
"license": "MIT",
"funding": {
"url": "https://github.com/wojtekmaj/date-utils?sponsor=1"
}
},
"node_modules/@xtuc/ieee754": { "node_modules/@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -7498,6 +7510,22 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.21.0"
},
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/dayjs": { "node_modules/dayjs": {
"version": "1.11.11", "version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
@@ -9474,6 +9502,52 @@
"url": "https://github.com/sponsors/rawify" "url": "https://github.com/sponsors/rawify"
} }
}, },
"node_modules/framer-motion": {
"version": "4.1.17",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-4.1.17.tgz",
"integrity": "sha512-thx1wvKzblzbs0XaK2X0G1JuwIdARcoNOW7VVwjO8BUltzXPyONGAElLu6CiCScsOQRI7FIk/45YTFtJw5Yozw==",
"license": "MIT",
"dependencies": {
"framesync": "5.3.0",
"hey-listen": "^1.0.8",
"popmotion": "9.3.6",
"style-value-types": "4.1.4",
"tslib": "^2.1.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"react": ">=16.8 || ^17.0.0",
"react-dom": ">=16.8 || ^17.0.0"
}
},
"node_modules/framer-motion/node_modules/@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"license": "MIT",
"optional": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
},
"node_modules/framer-motion/node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"license": "MIT",
"optional": true
},
"node_modules/framesync": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz",
"integrity": "sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/fresh": { "node_modules/fresh": {
"version": "0.5.2", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -9625,6 +9699,18 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/get-user-locale": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-3.0.0.tgz",
"integrity": "sha512-iJfHSmdYV39UUBw7Jq6GJzeJxUr4U+S03qdhVuDsR9gCEnfbqLy9gYDJFBJQL1riqolFUKQvx36mEkp2iGgJ3g==",
"license": "MIT",
"dependencies": {
"memoize": "^10.0.0"
},
"funding": {
"url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1"
}
},
"node_modules/glob": { "node_modules/glob": {
"version": "7.2.3", "version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -9873,6 +9959,12 @@
"he": "bin/he" "he": "bin/he"
} }
}, },
"node_modules/hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==",
"license": "MIT"
},
"node_modules/hoist-non-react-statics": { "node_modules/hoist-non-react-statics": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -13265,6 +13357,21 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/memoize": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/memoize/-/memoize-10.2.0.tgz",
"integrity": "sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==",
"license": "MIT",
"dependencies": {
"mimic-function": "^5.0.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sindresorhus/memoize?sponsor=1"
}
},
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -13341,6 +13448,18 @@
"node": ">=6" "node": ">=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==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-indent": { "node_modules/min-indent": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -14092,6 +14211,18 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/popmotion": {
"version": "9.3.6",
"resolved": "https://registry.npmjs.org/popmotion/-/popmotion-9.3.6.tgz",
"integrity": "sha512-ZTbXiu6zIggXzIliMi8LGxXBF5ST+wkpXGEjeTUDUOCdSQ356hij/xjeUdv0F8zCQNeqB1+PR5/BB+gC+QLAPw==",
"license": "MIT",
"dependencies": {
"framesync": "5.3.0",
"hey-listen": "^1.0.8",
"style-value-types": "4.1.4",
"tslib": "^2.1.0"
}
},
"node_modules/possible-typed-array-names": { "node_modules/possible-typed-array-names": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
@@ -15584,6 +15715,31 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
}, },
"node_modules/react-calendar": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-6.0.0.tgz",
"integrity": "sha512-6wqaki3Us0DNDjZDr0DYIzhSFprNoy4FdPT9Pjy5aD2hJJVjtJwmdMT9VmrTUo949nlk35BOxehThxX62RkuRQ==",
"license": "MIT",
"dependencies": {
"@wojtekmaj/date-utils": "^2.0.2",
"clsx": "^2.0.0",
"get-user-locale": "^3.0.0",
"warning": "^4.0.0"
},
"funding": {
"url": "https://github.com/wojtekmaj/react-calendar?sponsor=1"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-dev-utils": { "node_modules/react-dev-utils": {
"version": "12.0.1", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -15809,6 +15965,29 @@
"react": "^16.0.0 || ^17.0.0 || ^18.0.0" "react": "^16.0.0 || ^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/react-material-ui-carousel": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/react-material-ui-carousel/-/react-material-ui-carousel-3.4.2.tgz",
"integrity": "sha512-jUbC5aBWqbbbUOOdUe3zTVf4kMiZFwKJqwhxzHgBfklaXQbSopis4iWAHvEOLcZtSIJk4JAGxKE0CmxDoxvUuw==",
"license": "MIT",
"dependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.4.1",
"@mui/material": "^5.4.1",
"@mui/system": "^5.4.1",
"framer-motion": "^4.1.17"
},
"peerDependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@mui/icons-material": "^5.0.0",
"@mui/material": "^5.0.0",
"@mui/system": "^5.0.0",
"react": "^17.0.1 || ^18.0.0",
"react-dom": "^17.0.2 || ^18.0.0"
}
},
"node_modules/react-redux": { "node_modules/react-redux": {
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
@@ -17374,6 +17553,16 @@
"webpack": "^5.0.0" "webpack": "^5.0.0"
} }
}, },
"node_modules/style-value-types": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-4.1.4.tgz",
"integrity": "sha512-LCJL6tB+vPSUoxgUBt9juXIlNJHtBMy8jkXzUJSBzeHWdBu6lhzHqCvLVkXFGsFIlNa2ln1sQHya/gzaFmB2Lg==",
"license": "MIT",
"dependencies": {
"hey-listen": "^1.0.8",
"tslib": "^2.1.0"
}
},
"node_modules/stylehacks": { "node_modules/stylehacks": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
@@ -18421,6 +18610,15 @@
"makeerror": "1.0.12" "makeerror": "1.0.12"
} }
}, },
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/watchpack": { "node_modules/watchpack": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",

View File

@@ -23,15 +23,18 @@
"apexcharts": "3.49.2", "apexcharts": "3.49.2",
"axios": "^1.7.3", "axios": "^1.7.3",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^2.29.3",
"dayjs": "1.11.11", "dayjs": "1.11.11",
"moment": "^2.30.1", "moment": "^2.30.1",
"notistack": "^3.0.1", "notistack": "^3.0.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-apexcharts": "1.4.1", "react-apexcharts": "1.4.1",
"react-calendar": "^6.0.0",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "7.52.0", "react-hook-form": "7.52.0",
"react-jwt": "^1.2.2", "react-jwt": "^1.2.2",
"react-material-ui-carousel": "^3.4.2",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router": "^7.1.1", "react-router": "^7.1.1",
"react-router-dom": "^6.25.1", "react-router-dom": "^6.25.1",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" ?>
<svg data-name="Layer 1" id="Layer_1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<title/>
<path d="M129.17,418.45a8,8,0,0,1-5.26,10,7.86,7.86,0,0,1-2.38.36,8,8,0,0,1-7.63-5.62l-4.53-14.54a8,8,0,1,1,15.28-4.76Zm67.39-20.83a8,8,0,1,0-15.27,4.75l4.52,14.54a8,8,0,0,0,7.64,5.63,7.87,7.87,0,0,0,2.38-.37,8,8,0,0,0,5.26-10Zm-35.95,3.14a8,8,0,0,0-15.28,4.75l4.52,14.54a8,8,0,0,0,7.64,5.63,8.18,8.18,0,0,0,2.38-.36,8,8,0,0,0,5.26-10ZM433.33,298c-25.41,44.26-54.84,78.43-87.46,101.56-16.81,11.92-59.44,24.56-84.91,32.12-5.32,1.57-9.92,2.94-13.11,4a370.71,370.71,0,0,1-112,17.74c-33.48,0-54.39-5-56-5.36a8,8,0,0,1-5.73-5.39L57.56,389.21v0a8.33,8.33,0,0,1-.22-.86s0-.08,0-.12c0-.24-.08-.49-.1-.73a2.62,2.62,0,0,0,0-.28c0-.19,0-.39,0-.58s0-.2,0-.3a5.42,5.42,0,0,1,.06-.58,2.51,2.51,0,0,1,0-.27c0-.24.09-.47.15-.7a.65.65,0,0,1,0-.13,7.67,7.67,0,0,1,.67-1.63l.1-.18a6.65,6.65,0,0,1,.36-.56l.06-.1.11-.13.36-.45.23-.26.14-.14,45-45A266.27,266.27,0,0,1,103,307.46c0-36.46,7-69.85,19.13-93-32.1,1.69-56,3.35-56.34,3.38a8,8,0,0,1-8.48-9.06c7-51.51,61.36-89.1,93.12-106.92,47.46-26.62,103.43-43.16,146.08-43.16,1.29,0,2.59,0,3.87,0C356.3,60,406.22,90,433.87,139,462,189,461.83,248.39,433.33,298ZM119,307.46a251.73,251.73,0,0,0,1.55,28,8,8,0,0,1,.59,4.8,196,196,0,0,0,7.16,33c24.81-3.44,53.26-9,78.26-17.87a183.14,183.14,0,0,0,28.72-12.84,56.36,56.36,0,0,0,25.1-29.89C283,250,289,222.42,289.07,214.33c-5.77-1.78-28.59-5.45-116.87-2.17-10.5.39-20.92.84-30.91,1.32C127.46,233.5,119,269,119,307.46ZM107.44,355.9,85.59,377.75c7.42-.53,16.47-1.31,26.56-2.44C110.32,369.16,108.74,362.66,107.44,355.9Zm312.5-209c-24.86-44.06-69.7-71-120-72.18q-1.74,0-3.51,0c-39.46,0-93.73,16.14-138.25,41.11-44.7,25.09-74.3,55.71-83,85.36,12.65-.81,35.41-2.2,61.57-3.47h.1c13.26-.64,27.39-1.25,41.53-1.74,33.33-1.15,60.17-1.4,79.77-.74,35.5,1.19,43.28,4.95,45.8,11.92,1.58,4.37,5.78,15.95-28.6,111a72.37,72.37,0,0,1-32.25,38.36,200,200,0,0,1-31.25,14c-50.19,17.85-111.61,22.66-136,23.91l12.12,39c16.47,3,78.12,11.44,155-13,3.34-1.06,8-2.44,13.4-4,22.91-6.8,65.56-19.44,80.2-29.83,30.73-21.78,58.6-54.24,82.85-96.48A143.53,143.53,0,0,0,419.94,146.89Zm-66.66,92.18a15.91,15.91,0,0,1,1.8,12.09L338.7,316.71a16,16,0,0,1-7.66,10l-16.79,9.47a16,16,0,0,1-23.34-17.79L310.5,240a16,16,0,0,1,19.37-11.62l13.58,3.39A15.91,15.91,0,0,1,353.28,239.07Zm-13.72,8.2L326,243.92l-19.54,78.32,16.74-9.43,16.37-65.53h0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,25 @@
<svg width="200" height="100" viewBox="0 0 220 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="220" height="110" fill="white"/>
<g transform="translate(7,28)">
<path d="M28.7238 27.0847V16.4433H32.2834V35.6217L20.213 24.7817V35.4231H16.6535V16.2447L28.7238 27.0847Z"
fill="#3C1642"/>
<path d="M36.3247 35.4231V16.4433H49.1845V19.2624H39.8842V24.7817H48.3549V27.6009H39.8842V32.604H49.5994V35.4231H36.3247Z"
fill="#3C1642"/>
<path d="M82.5168 35.3932L89.1492 0.0340271H95.7815L86.431 44.4732H79.1462L72.3182 12.151L65.4684 44.4732H58.2054L48.8549 0.0340271H55.4655L62.1196 35.3622L69.1868 0.0340271H75.4278L82.5168 35.3932Z"
fill="#1DD3B0"/>
<path d="M95.8258 16.4432H103.453C105.3 16.4432 106.968 16.8491 108.458 17.6609C109.93 18.4727 111.09 19.6021 111.937 21.0492C112.767 22.4963 113.182 24.1243 113.182 25.9332C113.182 27.742 112.767 29.37 111.937 30.8171C111.081 32.2818 109.921 33.4113 108.458 34.2054C106.968 35.0172 105.3 35.4231 103.453 35.4231H95.8258V16.4432ZM99.3853 32.6039H103.025C104.863 32.6039 106.424 31.9686 107.709 30.698C108.985 29.4185 109.622 27.8303 109.622 25.9332C109.622 24.0007 108.985 22.4037 107.709 21.1419C106.442 19.8889 104.881 19.2624 103.025 19.2624H99.3853V32.6039Z"
fill="#3C1642"/>
<path d="M116.407 35.4231V16.4432H119.966V35.4231H116.407Z" fill="#3C1642"/>
<path d="M124.008 35.4231V16.4432H137.068V19.2624H127.554V24.7817H136.239V27.6008H127.567V35.4231H124.008Z"
fill="#3C1642"/>
<path d="M141.11 35.4231V16.4432H154.17V19.2624H144.656V24.7817H153.341V27.6008H144.669V35.4231H141.11Z"
fill="#3C1642"/>
<path d="M158.211 35.4231V16.4432H171.071V19.2624H161.771V24.7817H170.242V27.6008H161.771V32.6039H171.486V35.4231H158.211Z"
fill="#3C1642"/>
<path d="M190.328 23.0875C190.328 24.5346 189.957 25.8052 189.217 26.8994C188.468 27.9935 187.41 28.7744 186.046 29.2421L189.966 35.4231H186.367L182.794 29.7053H179.087V35.4231H175.527V16.4432H183.075C185.314 16.4432 187.085 17.0609 188.387 18.2962C189.681 19.5403 190.328 21.1374 190.328 23.0875ZM179.074 19.2624V26.8861H182.713C183.864 26.8861 184.832 26.5199 185.617 25.7876C186.385 25.0552 186.768 24.1552 186.768 23.0875C186.777 22.0286 186.398 21.1242 185.631 20.3742C184.855 19.633 183.882 19.2624 182.713 19.2624H179.074Z"
fill="#3C1642"/>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M28.0759 2.30326C14.3594 2.30326 3.24006 13.2249 3.24006 26.6975C3.24006 40.1701 14.3594 51.0918 28.0759 51.0918H177.091C190.807 51.0918 201.927 40.1701 201.927 26.6975C201.927 13.2249 190.807 2.30326 177.091 2.30326H90.2617V0.0340289H177.091C192.083 0.0340289 204.237 11.9717 204.237 26.6975C204.237 41.4234 192.083 53.361 177.091 53.361H28.0759C13.0835 53.361 0.929749 41.4234 0.929749 26.6975C0.929749 11.9717 13.0835 0.0340271 28.0759 0.0340271H55.6071V2.30326H28.0759Z"
fill="#1DD3B0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

View File

@@ -0,0 +1,460 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px"
y="0px"
width="150" height="75"
viewBox="0 0 160 80" style="enable-background:new 0 0 150 75;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#989695;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#00A0E3;}
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#0A5CAC;}
.st4{fill:#989695;}
.st5{fill:#989695;stroke:#989695;stroke-width:0.1417;stroke-miterlimit:10;}
</style>
<rect width="160" height="80" fill="white"/>
<g transform="translate(5,15)">
<g>
<g>
<path class="st0" d="M25.1,17.4c-0.1-1.5-0.5-2.8-1.2-3.8c-0.3-0.4-0.7-0.8-1.1-1.1c-0.4-0.3-0.9-0.5-1.3-0.5
c0.4,0.3,0.7,0.7,1,1.1c0.8,1.2,1.2,2.6,1.4,4.3c0.1,1.6,0.1,3.3,0,5c-0.2,2.4-0.6,4.7-1.1,7c-0.5,2.3-1.2,4.2-1.9,5.7
c-0.7,1.4-1.6,2.9-2.6,4.4c-1.1,1.6-2.3,2.9-3.7,3.9c-0.4,0.3-0.7,0.5-1.1,0.7c0.9-0.4,1.9-0.9,2.7-1.6c1.3-1,2.4-2.2,3.4-3.7
c1-1.5,1.9-2.9,2.5-4.3c0.7-1.4,1.3-3.2,1.8-5.5c0.5-2.2,0.9-4.5,1.1-6.8C25.2,20.6,25.2,19,25.1,17.4L25.1,17.4z"/>
<path class="st0" d="M51.4,34c-0.5-0.3-0.9-0.6-1.1-1.1l0,7.5c0,1.1,0.4,1.4,0.5,1.5c0.4,0.3,0.8,0.5,1.3,0.5
c-0.4-0.5-0.6-1.1-0.6-2v-6.3C51.5,34.1,51.4,34,51.4,34L51.4,34z"/>
<path class="st0" d="M63.1,37.6c-0.3-0.7-0.9-1.4-1.6-1.9c-0.6-0.4-1.3-0.8-2-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.9,0.6,1.6,1.4,2,2.3
c0.4,1,0.5,2.1,0.2,3.2c-0.3,1-0.7,1.9-1.4,2.6c-0.2,0.2-0.4,0.5-0.7,0.7c0.9-0.2,1.6-0.7,2.2-1.3c0.5-0.6,0.9-1.4,1.1-2.2
C63.5,39.2,63.5,38.4,63.1,37.6L63.1,37.6z"/>
<path class="st0" d="M54.6,29c0,0.7-0.2,1.3-0.6,1.8c-0.3,0.4-0.6,0.6-1,0.8c0,0.1,0.1,0.3,0.1,0.4c0.1,0.1,0.3,0.3,0.6,0.4
c0.3,0.2,0.7,0.3,1.1,0.5c-0.1-0.1-0.3-0.3-0.4-0.4c-0.2-0.3-0.3-0.6-0.3-0.8c0-0.5,0.2-0.8,0.5-0.9c0.3-0.1,0.6-0.3,0.8-0.6
c0.3-0.3,0.4-0.7,0.4-1.1c0-0.7-0.4-1.1-1.2-1.1c-0.1,0-0.2,0-0.3,0C54.5,28.2,54.6,28.6,54.6,29L54.6,29z"/>
<path class="st0" d="M52.2,23.6c0,0.7-0.3,1.2-0.9,1.5c-0.1,0.1-0.4,0.2-0.7,0.6c-0.3,0.3-0.3,0.6-0.3,0.7v1.5
c0.3-0.4,0.8-0.7,1.3-0.9v-0.6c0-0.5,0.2-0.9,0.5-1.4c0.3-0.4,0.7-0.7,1.1-0.9c0.2-0.1,0.3-0.2,0.3-0.4c0-0.1-0.1-0.2-0.3-0.2
L52.2,23.6L52.2,23.6L52.2,23.6z"/>
<path class="st0" d="M11.4,13.8L11.4,13.8L11.4,13.8c0,0.9-0.7,1.2-1,1.4c-0.7,0.3-1,0.9-1.1,1.7c0,0.3-0.1,0.7,0,1
c0,0.4,0.1,0.8,0.2,1.2c0.1,0.7,0.3,1.4,0.5,1.9c1.3,3.5,3.1,6.5,5.3,8.9c0.8,0.9,1.7,1.7,2.8,2.5c0,0,0-0.1,0.1-0.1l0-0.1l0-0.1
c0,0,0,0,0-0.1c-0.5-0.4-1-0.9-1.4-1.4c-2.3-2.5-4.1-5.6-5.5-9.2c-0.2-0.6-0.4-1.3-0.5-2.1c-0.1-0.4-0.1-0.8-0.2-1.2
c0-0.4,0-0.9,0-1.3c0.1-1.1,0.7-1.9,1.6-2.5c0.3-0.1,0.4-0.2,0.4-0.3c0-0.2-0.1-0.3-0.3-0.3h-1C11.4,13.7,11.4,13.8,11.4,13.8
L11.4,13.8z"/>
<path class="st0" d="M28.2,37.4c-0.4-0.2-0.8-0.4-1.1-0.4c0.2,0.2,0.3,0.4,0.5,0.7c0.3,0.6,0.4,1.3,0.3,1.9
c-0.1,0.7-0.4,1.3-1,1.9c-0.1,0.1-0.1,0.1-0.1,0.2c0.3,0,0.4-0.1,0.6-0.3c0.1-0.1,0.2-0.4,0.6-1.2c0.3-0.6,0.5-1.4,0.7-2.3
c0,0,0-0.1,0-0.1C28.5,37.7,28.4,37.5,28.2,37.4L28.2,37.4z"/>
<path class="st0" d="M43.1,25.1c0.1-0.1,0.2-0.3,0.3-0.4c-0.1-0.2-0.2-0.3-0.3-0.5c-0.1,0.4-0.4,0.8-0.9,1
c-0.1,0.1-0.3,0.2-0.7,0.6c-0.3,0.3-0.3,0.6-0.3,0.7v14.9c0,0.2,0.1,0.4,0.3,0.6c0.2,0.3,0.5,0.5,0.7,0.6l0,0l0,0
c0.2,0.1,0.4,0.3,0.6,0.5l0,0l0,0c0.1,0.1,0.1,0.2,0.1,0.3c0-0.1,0-0.1,0.1-0.2l0,0l0,0c0.1-0.1,0.1-0.2,0.2-0.3
c-0.1-0.1-0.2-0.2-0.3-0.3c-0.3-0.4-0.5-0.8-0.5-1.3V26.5C42.5,26,42.7,25.5,43.1,25.1L43.1,25.1z"/>
<path class="st0" d="M34.6,25.5c0,0-0.1,0-0.1,0c-0.4,0-1,0.1-1.2,0.4c-0.3,0.4-0.4,0.8-0.4,1.3c-0.1,0.7-0.1,1.4-0.2,2.2
c0,1.2,0,2.3,0,3.5c-0.1,2-0.3,3.8-0.6,5.3c-0.2,1-0.5,1.8-0.8,2.5c-0.3,0.7-0.5,1.2-0.7,1.4h0c-0.4,0.9-0.9,1.6-1.4,2.1
c0,0,0.1,0,0.1,0c1.1-0.1,2.1-1.1,2.9-3.1c0.7-1.7,1.1-3.9,1.3-6.4c0.2-2.6,0.4-5,0.6-7.4C34.1,26.6,34.3,26,34.6,25.5L34.6,25.5
z"/>
<path class="st0" d="M111.1,43.5c-0.4-0.2-0.7-0.4-1.1-0.8c-0.3-0.4-0.5-0.8-0.5-1.3l0-4.7c-0.4,0.1-0.8,0.3-1.3,0.3v4.3
c0,0.2,0.1,0.4,0.3,0.6c0.2,0.3,0.5,0.5,0.7,0.6l0,0l0,0c0.3,0.1,0.5,0.4,0.7,0.6c0.2,0.3,0.2,0.6,0.2,0.8h1
c0.2,0,0.3-0.1,0.2-0.3C111.3,43.6,111.2,43.6,111.1,43.5L111.1,43.5z"/>
<path class="st0" d="M110.2,23.6c0.1,0.7-0.3,1.2-0.9,1.5c-0.2,0.1-0.4,0.3-0.7,0.6c-0.3,0.3-0.3,0.6-0.3,0.7v7.6
c0.4-0.1,0.8-0.2,1.3-0.3v-7.3c0-0.5,0.2-0.9,0.5-1.4c0.3-0.4,0.7-0.7,1.1-0.9c0.2-0.1,0.3-0.2,0.3-0.4c0-0.1-0.1-0.2-0.2-0.2
L110.2,23.6L110.2,23.6L110.2,23.6z"/>
<path class="st0" d="M125,52c-1-0.7-1.9-1.5-2.6-2.7c-0.6-0.9-1.1-2-1.5-3.1c-0.4-1.1-0.7-2.2-1.1-3.2c-0.4-1.2-0.8-2.3-1.3-3.4
c-0.4-1.1-1-2-1.6-2.8c-0.5-0.5-0.9-1-1.2-1.4c-0.4-0.4-0.8-0.7-1.3-0.9c0.7-0.3,1.4-0.7,1.9-1.1c0.6-0.4,1.3-1,1.9-1.7
c0.7-0.8,1.2-1.6,1.6-2.5c0.3-0.7,0.6-1.6,0.8-2.7c0.2-1.1,0-2-0.5-2.7c-0.5-0.7-1-1-1.7-1.1c0,0-0.1,0-0.1,0
c0.1,0.1,0.3,0.3,0.4,0.5c0.7,1,0.9,2.2,0.7,3.5c-0.2,1.1-0.5,2.1-0.9,3c-0.5,1-1,1.9-1.8,2.7c-0.7,0.8-1.4,1.5-2.1,1.9
c-0.2,0.1-0.3,0.2-0.5,0.3c0,0,0,0,0,0c0.4,0.4,0.8,0.9,1.3,1.5c0.7,0.8,1.3,1.9,1.8,3c0.4,1.1,0.9,2.3,1.3,3.4
c0.4,1,0.7,2.1,1.1,3.3c0.3,1,0.8,2,1.3,2.8c0.6,1,1.4,1.8,2.3,2.4c0.4,0.3,0.6,0.6,0.6,1.1c0.2,0,0.4,0.1,0.6,0.1
c0.2,0,0.4,0,0.5,0C125.1,52.2,125.1,52.1,125,52L125,52z"/>
<path class="st0" d="M89.7,23.6c0,0.7-0.3,1.2-0.9,1.5c-0.2,0.1-0.4,0.3-0.7,0.6c-0.2,0.3-0.3,0.5-0.3,0.7l-0.2,4.9h1.3l0.2-5
c0-0.5,0.2-0.9,0.5-1.4c0.3-0.4,0.7-0.7,1.1-0.9c0.1-0.1,0.2-0.1,0.3-0.2c0-0.1,0-0.1,0-0.2v0l0,0c0,0,0,0,0,0
c0,0-0.1-0.1-0.2-0.1L89.7,23.6L89.7,23.6L89.7,23.6z"/>
<path class="st0" d="M90,43.5c-0.4-0.2-0.7-0.4-1-0.8c-0.3-0.4-0.5-0.8-0.4-1.3l0.2-6.8h-1.3l-0.2,6.8c0,0.2,0.1,0.4,0.2,0.6
c0.2,0.3,0.4,0.4,0.6,0.5c0.3,0.1,0.6,0.4,0.8,0.7l0,0l0,0.1C89,43.6,89,43.9,89,44h1c0.2,0,0.3-0.1,0.2-0.3
C90.2,43.6,90.1,43.6,90,43.5L90,43.5z"/>
<path class="st0" d="M67.7,30.5c-0.3-0.9-0.3-1.9,0-2.8c0.3-0.8,0.8-1.6,1.6-2.2c-0.6,0.1-1.1,0.4-1.6,0.8
c-0.6,0.5-1.1,1.1-1.3,1.8c-0.2,0.7-0.3,1.4,0,2.1c0.3,0.9,0.7,1.5,1.5,1.9c0.3,0.2,0.8,0.4,1.3,0.6C68.5,32.1,68,31.4,67.7,30.5
L67.7,30.5z"/>
<path class="st0" d="M80.2,25.1L80.2,25.1l0,0.1c0,0.7-0.3,1.2-0.9,1.5c-0.2,0.1-0.4,0.3-0.7,0.6c-0.2,0.3-0.3,0.5-0.3,0.8v13.2
c0,0.2,0.1,0.4,0.3,0.6c0.2,0.3,0.5,0.5,0.7,0.5l0,0l0,0c0.2,0.1,0.4,0.3,0.6,0.5l0,0.1l0,0.1c0,0.1,0.1,0.1,0.1,0.2
c0-0.1,0.1-0.1,0.1-0.2c0.1-0.1,0.1-0.1,0.2-0.2c-0.1-0.1-0.2-0.2-0.3-0.3c-0.3-0.4-0.5-0.8-0.5-1.3l0-13.2
c0-0.5,0.2-0.9,0.5-1.4c0.3-0.5,0.7-0.8,1.1-0.9c0.2-0.1,0.3-0.2,0.3-0.4c0-0.1-0.1-0.2-0.3-0.2c-0.4-0.1-0.7-0.1-1.1-0.2
C80.1,25,80.1,25,80.2,25.1L80.2,25.1z"/>
<path class="st0" d="M72.2,36.1l-0.3,0c-0.2,0-0.4,0-0.6,0c0,0-0.1,0.1-0.1,0.2c-0.3,0.4-0.7,1.1-1,2.1c-0.3,1-0.6,1.9-0.8,2.8
c-0.2,0.7-0.3,1.4-0.5,2.1c-0.2,0.7-0.4,1.5-0.6,2.2c-0.2,0.6-0.4,1.2-0.7,1.7l-0.8,1.5c-0.6,0.9-1.4,2-2.4,3.2
c-0.4,0.4-0.8,0.8-1.3,1.1c1.1-0.4,2-1,2.8-1.8c1-1.1,1.7-2.2,2.3-3c0.3-0.5,0.6-1,0.8-1.4c0.3-0.5,0.5-1,0.6-1.5
c0.2-0.7,0.4-1.4,0.5-2.2c0.2-0.7,0.3-1.4,0.5-2.1c0.2-0.9,0.5-1.8,0.9-2.9C71.6,37.2,71.9,36.6,72.2,36.1L72.2,36.1z"/>
<path class="st0" d="M99.1,25.1c-0.1,0-0.3,0.2-0.6,0.6c-0.2,0.3-0.2,0.5-0.2,0.7l1,14.9c0,0.2,0.1,0.4,0.3,0.7
c0.3,0.3,0.5,0.5,0.8,0.6c0.3,0.1,0.5,0.3,0.7,0.6c0,0,0,0.1,0.1,0.1c0.1-0.1,0.2-0.2,0.2-0.3c-0.1-0.1-0.2-0.2-0.3-0.3
c-0.4-0.4-0.6-0.8-0.6-1.3l-1-14.9c0-0.5,0.1-0.9,0.4-1.4c0.3-0.4,0.7-0.7,1-0.9c0,0,0.1,0,0.1,0c0-0.2,0-0.3,0-0.5c0,0,0,0,0,0
c0,0,0,0-0.1,0h-1C100.1,24.3,99.7,24.9,99.1,25.1L99.1,25.1z"/>
<path class="st0" d="M127.7,17.7c-0.3,0.1-0.5,0.3-0.7,0.5c0,0,0,0.1,0,0.1c0.2,0.2,0.3,0.3,0.5,0.1c0.1-0.1,0.2-0.2,0.3-0.2
c0-0.2,0.1-0.4,0.1-0.6C127.8,17.6,127.8,17.7,127.7,17.7L127.7,17.7z"/>
<path class="st0" d="M131.9,20.7c0.2-1,0.5-1.9,0.7-2.8c-0.4-0.3-0.7-0.5-1.1-0.6c-0.3,1.2-0.5,2.4-0.8,3.7
c-0.3,1.2-0.6,2.4-0.9,3.6h1.2C131.3,23.2,131.6,22,131.9,20.7L131.9,20.7z"/>
<path class="st0" d="M149.1,43.1c-0.9-0.6-1.5-1.3-1.9-1.9c-0.4-0.6-0.7-1.3-0.8-2l-5.1-21.7c-0.5-2-1.4-3.3-2.8-4
c-0.3-0.1-0.6-0.2-0.9-0.3c1.2,0.9,2,2.2,2.4,4.1l5.1,21.7c0.1,0.6,0.4,1.2,0.7,1.7c0.3,0.5,0.8,1,1.6,1.6c0.5,0.3,0.9,0.7,1,1.3
l0,0l0,0c0,0.2,0,0.3,0,0.4h1c0.2,0,0.3-0.1,0.3-0.3C149.5,43.5,149.4,43.3,149.1,43.1L149.1,43.1z"/>
<path class="st0" d="M131.2,43.4c-0.6-0.3-1.1-0.8-1.3-1.4c-0.2-0.6-0.4-1.3-0.5-2.1c-0.2-1.3-0.2-2.7-0.1-4.1
c0.1-1.4,0.3-2.9,0.5-4.4c0.1-1,0.3-2.1,0.6-3.2H129c-0.2,1.2-0.4,2.3-0.6,3.3c-0.2,1.4-0.4,2.9-0.5,4.3c-0.1,1.3,0,2.7,0.1,3.9
c0.1,0.7,0.2,1.3,0.5,1.9c0.1,0.4,0.4,0.7,0.8,0.9l0,0l0,0c0.5,0.4,0.8,0.6,0.8,1.2c0,0.1,0,0.2,0,0.3h1c0.2,0,0.3-0.1,0.3-0.3
C131.6,43.7,131.4,43.6,131.2,43.4L131.2,43.4z"/>
</g>
<path class="st1" d="M134.7,24.3l-0.8-3.4c-0.3-1.4-0.9-2.8-2.2-3.3c-0.3,1.1-0.5,2.3-0.8,3.4c-0.3,1.1-0.5,2.2-0.8,3.3H134.7
L134.7,24.3z M126.6,18.8c-0.2,0.3-0.4,0.5-0.7,0.6c-0.3,0.2-0.6,0.3-0.9,0.3c-0.5,0-1-0.3-1.3-0.7c-0.4-0.5-0.5-1.1-0.4-1.7
c0.1-0.2,0.1-0.4,0.2-0.6c0.7-1.7,1.8-3.1,3.4-4c1.4-0.8,2.9-1.3,4.5-1.3l0.2,0c1.7,0,3.4,0.3,4.9,1.1c2,0.9,3,2.8,3.5,4.8
l5.1,21.7c0.1,0.6,0.3,1.1,0.7,1.6c0.4,0.6,1,1.1,1.5,1.5c0.6,0.3,1,0.8,1.1,1.4l0,0l0,0c0,0.4-0.1,0.9-0.4,1.2
c-0.3,0.3-0.7,0.5-1.2,0.5l-8.7,0c-0.7,0-1.4-0.4-1.6-1.1c-0.3-0.8,0.2-1.4,0.8-1.8l0.1,0l0.1,0c0.3-0.2,0.6-0.5,0.7-0.8
c0.2-0.4,0.3-0.7,0.2-1.1l-2.8-11.9h-6.5c-0.2,1-0.4,2.1-0.5,3.1c-0.2,1.4-0.4,2.8-0.5,4.3c-0.1,1.3-0.1,2.6,0.1,3.8
c0.1,0.6,0.2,1.2,0.4,1.8c0.1,0.4,0.4,0.6,0.7,0.8l0.1,0l0.1,0c0.5,0.4,1,0.7,1,1.4c0,0.9-0.7,1.6-1.6,1.6l-7.6,0
c-0.7,0-1.3-0.2-1.6-0.8c-0.2-0.5-0.2-1,0.1-1.5c0-0.1,0.1-0.1,0.1-0.2l0,0l0,0c0.7-1.1,1.3-2.3,1.8-3.5c0.6-1.3,1.1-2.7,1.6-4.1
c0.5-1.5,0.9-3,1.3-4.5c0.4-1.4,0.7-2.9,1-4.3c0.3-1.5,0.7-2.9,1-4.3c0.3-1.3,0.6-2.7,0.9-4C127.2,18.2,126.9,18.5,126.6,18.8
L126.6,18.8z M17.9,31.9L17.9,31.9c0.5-1.1,0.8-2.3,1-3.4c0.2-1.3,0.2-2.7,0-4.1c-0.1-1-0.4-2.1-0.7-3.1c-0.3-1-0.7-2-1.2-2.9
c-0.2-0.4-0.4-0.7-0.6-1.1l0-0.1c-0.2-0.4-0.5-0.9-0.6-1.3c-0.2-0.5-0.3-1-0.3-1.5c0-1.3,0.5-2.4,1.5-3.1c1.3-1,3-0.9,4.3,0.1
c0.5,0.4,1,0.9,1.4,1.4c0.9,1.3,1.3,2.9,1.4,4.4c0.1,1.7,0.1,3.4,0,5.1c-0.2,2.4-0.6,4.7-1.1,7c-0.5,1.9-1,3.9-1.9,5.7
c-0.7,1.6-1.7,3.1-2.6,4.5c-1,1.5-2.3,2.9-3.7,4c-2.2,1.6-4.6,2.6-7.3,2.6c-0.1,0-0.3,0-0.4,0l0,0c-0.8,0-1.5-0.1-2.3-0.3
c-0.7-0.1-1.4-0.3-2-0.6c-1.6-0.9-2.5-2.4-1.9-4.3c0.5-1.8,1.9-2.7,3.8-2.7l0.2,0c0.5,0,1.1,0.2,1.6,0.4c0.4,0.2,0.8,0.4,1.1,0.6
c0.5,0.2,0.9,0.4,1.4,0.6c0.4,0.2,0.9,0.3,1.3,0.4l0,0c0.8,0.1,1.6,0.1,2.4-0.3c0.6-0.3,1.1-0.7,1.6-1.2c0.2-0.2,0.4-0.5,0.6-0.7
c-1.3-0.9-2.6-1.8-3.8-2.9c-1.9-1.7-3.3-3.9-4.5-6.2c-0.9-1.8-1.7-3.6-2.3-5.5c-0.7-1.9-1.2-3.8-1.6-5.8c-0.1-0.5-0.3-1-0.6-1.4
c-0.2-0.3-0.5-0.7-0.8-0.8C0.5,15.1,0,14.7,0,14v0l0,0c0-0.9,0.7-1.5,1.6-1.5h8.5c0.8,0,1.5,0.6,1.6,1.4l0,0.1l0,0.1
c0,0.8-0.5,1.2-1.1,1.5c-0.6,0.3-0.9,0.8-0.9,1.5l0,0c0,0.3-0.1,0.6,0,1c0,0.4,0.1,0.8,0.2,1.2c0.1,0.6,0.2,1.2,0.5,1.8
c1.2,3.2,2.9,6.3,5.2,8.8C16.2,30.5,17,31.2,17.9,31.9L17.9,31.9z M50.5,33.6v6.8c0,0.4,0,1,0.4,1.3c0.4,0.3,0.8,0.4,1.2,0.4
c0.1,0,0.3,0,0.4,0c0.7,0,1.7-0.1,2.3-0.5c0.9-0.6,1.2-1.5,1.2-2.6c0-0.6-0.1-1.1-0.2-1.6c-0.2-0.5-0.4-0.8-0.8-1.1
c-0.5-0.4-1.1-0.7-1.7-0.9c-0.7-0.3-1.4-0.7-2-1.2C51,34,50.7,33.8,50.5,33.6L50.5,33.6z M43.1,24.8c-0.2,0.3-0.5,0.5-0.8,0.6
c-0.2,0.1-0.4,0.4-0.6,0.5c-0.1,0.2-0.2,0.3-0.2,0.6v14.9c0,0.2,0.1,0.3,0.2,0.5c0.2,0.2,0.4,0.4,0.6,0.5l0,0l0,0
c0.3,0.1,0.5,0.3,0.7,0.6l0,0c0.2-0.2,0.4-0.4,0.6-0.6l0.1,0l0.1,0c0.2-0.1,0.4-0.3,0.6-0.5c0.1-0.1,0.2-0.3,0.2-0.5l0-14.9
c0-0.2-0.1-0.4-0.2-0.6c-0.1-0.2-0.3-0.4-0.6-0.5C43.5,25.2,43.3,25,43.1,24.8L43.1,24.8z M43.1,22.9c0.3-0.4,0.7-0.6,1.2-0.6h6.6
c0.7,0,1.4,0.4,1.5,1.2l0,0.1l0,0.1c0.1,0.8-0.4,1.4-1.1,1.7c-0.2,0.1-0.4,0.3-0.6,0.5c-0.1,0.2-0.2,0.3-0.2,0.6v0.9
c0.5-0.5,1.2-0.7,1.9-0.7c1.4,0,2.4,0.9,2.4,2.4c0,0.7-0.2,1.4-0.7,1.9c-0.3,0.3-0.5,0.6-0.9,0.8c0,0,0,0,0,0
c0.1,0.2,0.4,0.3,0.5,0.4c0.5,0.2,1,0.4,1.5,0.6c0.7,0.2,1.3,0.4,2,0.6c0.9,0.3,1.8,0.8,2.6,1.4c0.9,0.6,1.6,1.4,2.1,2.4
c0.5,1.1,0.6,2.2,0.3,3.3c-0.3,1-0.7,1.9-1.4,2.7c-0.9,1.1-2.1,1.7-3.5,1.9c-1.3,0.2-2.7,0.3-4,0.3l-5.6,0v0h-3.4
c-0.5,0-0.9-0.2-1.2-0.5c-0.3,0.4-0.7,0.6-1.2,0.6h-6.6c-0.5,0-1-0.2-1.3-0.7c-0.3-0.4-0.3-0.9-0.1-1.4c0.2-0.4,0.5-0.7,0.8-0.9
l0.1,0l0.1,0c0.2-0.1,0.4-0.3,0.6-0.5c0.1-0.1,0.2-0.3,0.2-0.5V27c0-0.3-0.2-0.8-0.4-1c-0.1-0.3-0.6-0.3-0.8-0.3
c-0.3,0-0.8,0-1,0.3c-0.2,0.4-0.4,0.8-0.4,1.2c-0.2,2.5-0.4,5-0.6,7.4c-0.2,2.3-0.6,4.7-1.4,6.8c-0.7,1.8-1.9,3.8-3.9,4
c-0.2,0-0.4,0-0.6,0c-1,0-2-0.3-2.8-0.9c-1.3-1-2-2.4-2.1-4c-0.1-1,0-2.2,0.6-3c1.1-1.7,2.7-2.2,4.5-1.2c0.5,0.3,0.9,0.8,1.2,1.3
c0.2,0.4,0.4,0.9,0.4,1.4c0.1-0.4,0.2-0.7,0.3-1.1c0.3-1.7,0.5-3.4,0.6-5.1c0.1-2,0.1-4-0.1-6c0-0.3-0.3-0.6-0.4-0.8
c-0.3-0.3-0.5-0.5-0.9-0.6c-0.8-0.2-1.3-1-1.2-1.8c0.1-0.8,0.7-1.3,1.5-1.3h14.1C42.4,22.3,42.8,22.5,43.1,22.9L43.1,22.9z
M72.7,26c0,0-0.1,0-0.1,0c-0.3,0-0.6-0.1-0.9-0.1c-0.4,0-0.8-0.1-1.2-0.1c-0.1,0-0.2,0-0.4,0c-0.2,0-0.3,0-0.5,0
c-0.6,0.1-1.2,0.4-1.7,0.8c-0.6,0.4-1,1-1.2,1.7c-0.2,0.6-0.2,1.3,0,1.9c0.2,0.8,0.7,1.4,1.3,1.8l0,0c0.7,0.5,1.7,0.7,2.6,0.8
c0.5,0.1,0.9,0.1,1.4,0.1l0.2,0c0.2,0,0.4,0,0.5,0V26L72.7,26z M101.2,42.9c0.2-0.2,0.3-0.3,0.5-0.5l0.1,0l0.1,0
c0.2-0.1,0.4-0.3,0.6-0.5c0.1-0.2,0.2-0.3,0.2-0.5V26.5c0-0.2-0.1-0.4-0.2-0.6c-0.1-0.2-0.3-0.4-0.5-0.5l0,0l0,0
c-0.7-0.3-1.1-1-1-1.7c0.1-0.8,0.7-1.3,1.5-1.3h6.6c0.7,0,1.4,0.5,1.5,1.2l0,0l0,0c0.1,0.8-0.3,1.5-1,1.8l0,0
c-0.2,0.1-0.4,0.3-0.6,0.5c-0.1,0.2-0.2,0.4-0.2,0.6v7.3c0.4-0.1,0.7-0.2,1.1-0.3c0.8-0.2,1.5-0.6,2.2-1c0.4-0.3,0.8-0.6,1.2-0.9
c0.3-0.3,0.6-0.7,0.8-1.1c0.2-0.4,0.3-0.9,0.2-1.3c-0.1-0.4-0.3-0.8-0.5-1.1c-0.3-0.5-0.6-1.1-0.7-1.7c-0.1-0.3-0.1-0.6-0.1-1
c0-0.5,0-1,0.1-1.4c0.5-1.6,1.8-2.5,3.5-2.4l0,0c1.1,0.1,2,0.7,2.7,1.6c0.8,1.1,0.9,2.4,0.7,3.7c-0.2,1-0.4,2.1-0.9,3
c-0.5,1-1.1,1.9-1.8,2.8c-0.6,0.7-1.4,1.4-2.2,2c-0.1,0.1-0.2,0.1-0.3,0.2c0.4,0.4,0.7,0.8,1.1,1.3c0.8,0.9,1.3,2,1.8,3.1
c0.5,1.1,0.9,2.3,1.3,3.5c0.4,1.1,0.7,2.2,1.1,3.3c0.3,1,0.8,1.9,1.3,2.8c0.6,0.9,1.3,1.7,2.2,2.3c0.5,0.3,0.7,0.8,0.7,1.3
c0,0.5-0.4,1-0.9,1.2c-0.3,0.1-0.6,0.2-0.9,0.2c-0.1,0-0.3,0-0.4,0c-1.7-0.2-3.3-0.7-4.6-1.7c-1.1-0.8-2-1.7-2.8-2.9
c-0.7-1.1-1.2-2.3-1.6-3.5c-0.3-0.7-0.5-1.5-0.7-2.2c-0.2-0.7-0.4-1.4-0.5-2c-0.2-0.8-0.5-1.6-0.7-2.5c-0.1-0.5-0.3-1-0.6-1.4
c-0.2-0.2-0.4-0.4-0.6-0.6c-0.4,0.1-0.9,0.3-1.4,0.4v4.1c0,0.2,0.1,0.3,0.2,0.5c0.2,0.2,0.4,0.4,0.6,0.5l0,0l0,0
c0.3,0.2,0.6,0.4,0.8,0.7c0.3,0.5,0.3,1,0,1.5c-0.3,0.5-0.8,0.7-1.3,0.7h-6.6c-0.4,0-0.8-0.1-1.1-0.4c-0.3,0.3-0.7,0.4-1.1,0.4
h-6.6c-0.5,0-1-0.2-1.3-0.6c-0.3-0.4-0.3-0.9-0.2-1.4l0-0.1l0,0c0.2-0.4,0.5-0.7,0.9-0.9l0,0l0,0c0.2-0.1,0.4-0.3,0.5-0.4
c0.1-0.1,0.2-0.3,0.1-0.4l-0.4-6.7h-5.5l-0.2,6.6c0,0.2,0,0.3,0.2,0.5c0.1,0.2,0.3,0.4,0.5,0.5c0.4,0.2,0.7,0.5,0.9,0.9l0,0.1
l0,0.1c0.2,0.5,0.1,1-0.2,1.4c-0.3,0.4-0.8,0.6-1.3,0.6h-6.6c-0.4,0-0.9-0.1-1.2-0.5c-0.3,0.3-0.7,0.4-1.1,0.4h-6.6
c-0.5,0-1-0.2-1.3-0.7c-0.3-0.4-0.3-1-0.1-1.4c0.2-0.5,0.5-0.8,1-1c0.2-0.1,0.4-0.3,0.6-0.5c0.1-0.2,0.2-0.3,0.2-0.5v-4.9
l-0.8-0.1c-0.2,0-0.4,0-0.5,0c0,0,0,0,0,0l0,0l0,0c-0.4,0.5-0.7,1.4-0.9,2c-0.3,0.9-0.6,1.8-0.8,2.8c-0.2,0.7-0.3,1.4-0.5,2.1
c-0.2,0.8-0.3,1.5-0.6,2.2c-0.2,0.6-0.4,1.2-0.8,1.8l-0.8,1.5c-0.7,1.1-1.5,2.2-2.4,3.2c-1.2,1.4-2.8,2.2-4.6,2.5l0,0
c-0.1,0-0.3,0-0.4,0c-0.3,0-0.5,0-0.7-0.1c-0.5-0.2-0.9-0.6-0.9-1.2c-0.1-0.6,0.2-1,0.6-1.3c0.6-0.5,1.2-1.6,1.5-2.3
c0.5-1.2,1-2.4,1.3-3.6c0.3-1.1,0.6-2.2,0.9-3.2c0.4-1.2,0.7-2.3,1.2-3.5c0.4-1.1,1-2.2,1.7-3.2c0.2-0.2,0.3-0.4,0.5-0.6
c-0.6-0.2-1.1-0.4-1.7-0.7c-0.6-0.3-1.2-0.7-1.8-1.2c-0.6-0.5-1.1-1.2-1.5-1.9c-1-1.6-1.3-3.4-0.6-5.3c0.6-1.7,2-2.9,3.7-3.6
c1.3-0.6,2.7-0.8,4.1-0.9c0.8,0,1.5,0,2.3,0c0.7,0,1.4,0.1,2.2,0.2c1.2,0.2,2.4,0.5,3.6,0.9c1.1,0.4,2.2,0.6,3.3,0.8
c0.7,0.1,1.2,0.5,1.4,1.2l0,0.1l0,0.1c0.1,0.8-0.4,1.4-1.1,1.7c-0.2,0.1-0.4,0.4-0.6,0.5c-0.1,0.2-0.3,0.4-0.3,0.6v13.2
c0,0.2,0.1,0.3,0.2,0.5c0.2,0.2,0.4,0.4,0.6,0.5l0,0l0,0c0.3,0.1,0.5,0.3,0.7,0.5l0,0c0.2-0.2,0.4-0.4,0.6-0.5l0,0l0,0
c0.2-0.1,0.5-0.3,0.7-0.5c0.1-0.1,0.2-0.3,0.2-0.5l0.5-14.9c0-0.2-0.1-0.4-0.2-0.5c-0.1-0.2-0.4-0.4-0.6-0.5c-0.7-0.3-1.1-1-1-1.7
c0.1-0.8,0.7-1.3,1.5-1.3h6.6c0.7,0,1.3,0.4,1.5,1.2l0,0.1l0,0.1c0.1,0.8-0.4,1.5-1.1,1.7c-0.2,0.1-0.4,0.3-0.6,0.5
c-0.1,0.2-0.2,0.4-0.3,0.6l-0.2,4.7h5.1l-0.3-4.6c0-0.2-0.1-0.4-0.3-0.6c-0.2-0.2-0.4-0.4-0.6-0.5c-0.7-0.3-1.1-0.9-1.1-1.6v0l0,0
c0.1-0.8,0.7-1.3,1.5-1.3h6.6c0.7,0,1.3,0.4,1.5,1.2l0,0l0,0c0.1,0.8-0.3,1.5-1,1.8c-0.2,0.1-0.4,0.3-0.5,0.5
c-0.1,0.2-0.2,0.3-0.2,0.5l1,14.9c0,0.2,0.1,0.4,0.3,0.5c0.2,0.2,0.4,0.4,0.7,0.5l0,0l0,0C100.8,42.5,101,42.6,101.2,42.9
L101.2,42.9z"/>
<g>
<g>
<path class="st2" d="M7.1,44.9c-0.8,0-1.5-0.1-2.1-0.3c-0.6,0-1.2-0.2-1.7-0.5c-1.3-0.7-1.7-1.7-1.4-2.9
c0.4-1.2,1.2-1.8,2.6-1.8l0.2,0c0.3,0,0.7,0.1,1.1,0.3c0.4,0.2,0.7,0.4,1,0.5c0.5,0.2,1,0.4,1.5,0.6c0.6,0.3,1.1,0.4,1.7,0.5
c0.3,0.1,0.6,0.1,1,0.1c0.7,0,1.5-0.2,2.2-0.5c0.7-0.3,1.4-0.8,2-1.4c0.5-0.5,1-1.1,1.4-1.7c0,0,0-0.1,0-0.2
c0-0.1,0-0.1-0.1-0.1c-1.6-0.9-3.2-2.1-4.6-3.3c-1.5-1.3-2.9-3.3-4.2-5.8c-0.8-1.6-1.6-3.4-2.3-5.3c-0.7-1.9-1.2-3.8-1.6-5.6
c-0.1-0.7-0.4-1.3-0.8-1.9c-0.4-0.6-0.8-1-1.3-1.2c-0.3-0.2-0.4-0.3-0.4-0.4c0-0.2,0.1-0.4,0.4-0.4h8.5c0.2,0,0.4,0.1,0.4,0.3
c0,0.1-0.1,0.2-0.4,0.4c-0.9,0.5-1.5,1.3-1.6,2.4c-0.1,0.4-0.1,0.8,0,1.3c0,0.4,0.1,0.8,0.2,1.2c0.1,0.8,0.3,1.5,0.5,2.1
c1.3,3.6,3.2,6.7,5.5,9.2c1,1.1,2.3,2.2,3.7,3.1c0,0,0.1,0,0.1,0c0,0,0,0,0.1,0c0.1,0,0.1-0.1,0.1-0.1c0,0,0.4-0.9,0.5-1.1
c0.5-1.1,0.8-2.3,1.1-3.7c0.2-1.3,0.3-2.8,0.1-4.4c-0.1-1.1-0.4-2.2-0.8-3.3c-0.4-1.1-0.8-2.2-1.3-3.1c-0.2-0.3-0.4-0.7-0.6-1.1
c-0.3-0.5-0.5-0.9-0.6-1.3c-0.1-0.3-0.2-0.7-0.2-1.1c0-0.9,0.4-1.7,1.1-2.2c0.4-0.3,0.8-0.4,1.3-0.4c0.5,0,1.1,0.2,1.5,0.5
c0.5,0.4,0.9,0.7,1.1,1.2c0.7,1,1.1,2.3,1.2,3.9c0.1,1.5,0.1,3.2,0,4.9c-0.2,2.3-0.6,4.6-1.1,6.8c-0.5,2.2-1.1,4-1.8,5.5
c-0.7,1.4-1.5,2.8-2.5,4.3c-1,1.5-2.2,2.7-3.5,3.7c-2.1,1.5-4.3,2.3-6.6,2.3C7.3,44.9,7.2,44.9,7.1,44.9z"/>
</g>
<g>
<path class="st2" d="M48.8,44.1C48.8,44.1,48.8,44.1,48.8,44.1l-4.5,0C44.1,44.1,44,44,44,44c0-0.1,0-0.2,0-0.3
c0.1-0.1,0.2-0.2,0.3-0.3c0.3-0.1,0.7-0.4,1-0.8c0.3-0.4,0.5-0.8,0.5-1.3V26.4c0-0.5-0.2-0.9-0.5-1.3c-0.3-0.4-0.7-0.7-1-0.9
c-0.3-0.1-0.4-0.3-0.3-0.5c0,0,0-0.1,0.1-0.1c0.1-0.1,0.1-0.1,0.3-0.1h6.6c0.2,0,0.3,0.1,0.3,0.2c0,0.2-0.1,0.4-0.4,0.5
c-0.4,0.2-0.7,0.5-1,0.9c-0.3,0.4-0.5,0.9-0.5,1.3l0,14c0,1,0.3,1.8,0.8,2.2c0.6,0.5,1.2,0.7,2,0.7c0.1,0,0.3,0,0.4,0
c1.4,0,2.4-0.2,3-0.7c1.1-0.8,1.6-1.9,1.7-3.5c0-0.7-0.1-1.4-0.3-2.1c-0.2-0.7-0.6-1.2-1.2-1.7c-0.4-0.3-1-0.7-1.9-1
c-0.9-0.4-1.5-0.8-1.8-1.1c-1-0.6-1.5-1.5-1.5-2.8c0-0.3,0-0.6,0.1-0.9c0.1-0.3,0.2-0.7,0.4-1c0.4-0.5,0.9-0.8,1.5-0.8
c0.8,0,1.2,0.4,1.2,1.2c0,0.4-0.1,0.8-0.4,1.2c-0.3,0.3-0.6,0.5-0.9,0.6c-0.3,0.1-0.4,0.3-0.4,0.8c0,0.2,0.1,0.5,0.3,0.8
c0.2,0.3,0.5,0.6,1,0.9c0.5,0.3,1.1,0.5,1.7,0.7c0.7,0.2,1.3,0.4,1.9,0.6c0.8,0.3,1.6,0.7,2.3,1.2c0.7,0.5,1.3,1.2,1.6,1.9
c0.4,0.8,0.4,1.6,0.2,2.5c-0.2,0.9-0.6,1.6-1.2,2.3c-0.7,0.8-1.6,1.3-2.8,1.5c-1.1,0.2-2.4,0.3-3.8,0.3L48.8,44.1z"/>
</g>
<g>
<path class="st2" d="M59.4,53.2c-0.1,0-0.2,0-0.3-0.1c-0.1-0.1-0.2-0.1-0.2-0.2c0,0,0-0.1,0.1-0.2c0.7-0.5,1.3-1.4,1.9-2.8
c0.5-1.2,1-2.5,1.4-3.8c0.4-1.3,0.7-2.4,0.9-3.2c0.4-1.2,0.7-2.3,1.1-3.4c0.4-1.1,0.9-2.1,1.5-2.9c0.6-0.8,1.2-1.3,1.7-1.8
c0.1,0,0.1-0.1,0.1-0.2c0-0.1-0.1-0.1-0.2-0.2c-0.4-0.1-0.9-0.2-1.3-0.3c-0.7-0.2-1.3-0.4-1.9-0.7c-0.6-0.3-1.1-0.7-1.6-1.1
c-0.5-0.4-0.9-0.9-1.3-1.5c-0.9-1.5-1-2.9-0.5-4.2c0.5-1.3,1.5-2.3,3-2.9c1-0.4,2.2-0.7,3.6-0.8c0.3,0,0.6,0,0.9,0
c0.4,0,0.9,0,1.3,0c0.7,0,1.4,0.1,2.1,0.2c1.2,0.2,2.4,0.5,3.4,0.9c1,0.4,2.2,0.7,3.6,0.9c0.2,0,0.3,0.1,0.4,0.3
c0,0.2-0.1,0.4-0.4,0.5c-0.4,0.2-0.7,0.5-1,0.9c-0.3,0.4-0.5,0.9-0.5,1.4v13.2c0,0.5,0.2,0.9,0.5,1.3c0.3,0.4,0.7,0.7,1,0.8
c0.1,0,0.2,0.1,0.3,0.2c0.1,0.2,0.1,0.3,0.1,0.3c0,0-0.1,0.1-0.3,0.1h-6.6c-0.1,0-0.2,0-0.3-0.1c0-0.1,0-0.2,0-0.3
c0.1-0.1,0.2-0.3,0.3-0.3c0.3-0.1,0.7-0.4,1-0.8c0.3-0.4,0.5-0.8,0.5-1.3v-5.8c0-0.1-0.1-0.2-0.2-0.2l-0.4,0l-1.4-0.1
c-0.3,0-0.5,0-0.7,0c-0.3,0.1-0.6,0.2-0.8,0.5c-0.4,0.5-0.8,1.3-1.1,2.3c-0.4,1-0.6,2-0.9,2.9c-0.2,0.7-0.3,1.4-0.5,2.1
c-0.2,0.8-0.4,1.5-0.5,2.2c-0.2,0.6-0.4,1.1-0.7,1.5L65.8,48c-0.5,0.9-1.3,1.9-2.3,3c-1,1.1-2.3,1.9-3.9,2.1
C59.6,53.2,59.5,53.2,59.4,53.2z M70.1,24.5c-0.2,0-0.5,0-0.7,0c-0.8,0.1-1.6,0.5-2.2,1c-0.8,0.6-1.3,1.4-1.6,2.2
c-0.3,0.9-0.3,1.8,0,2.7c0.3,1.1,1,1.9,1.9,2.4c0.7,0.5,1.7,0.8,3,1c0.5,0.1,1.1,0.1,1.6,0.1c0,0,0.8,0,1.1,0c0,0,0.6,0,0.6,0
c0.1,0,0.1,0,0.1-0.1c0,0,0.1-0.1,0.1-0.1v-8.4c0-0.2-0.1-0.4-0.4-0.5c-0.2-0.1-0.5-0.2-0.8-0.2l-1-0.1c-0.4,0-0.9-0.1-1.3-0.1
C70.3,24.5,70.2,24.5,70.1,24.5z"/>
</g>
<g>
<path class="st2" d="M93.5,44.1c-0.2,0-0.3-0.1-0.3-0.1c-0.1-0.1-0.1-0.2,0-0.3c0.1-0.1,0.2-0.2,0.3-0.3c0.3-0.2,0.7-0.4,1-0.8
c0.3-0.4,0.4-0.8,0.4-1.3l-0.5-7.6c0-0.1-0.1-0.2-0.2-0.2h-7.4c-0.1,0-0.2,0.1-0.2,0.2l-0.2,7.6c0,0.5,0.1,0.9,0.4,1.3
c0.3,0.4,0.6,0.7,1,0.8c0.1,0.1,0.2,0.2,0.3,0.3c0.1,0.2,0,0.3,0,0.3c0,0-0.1,0.1-0.3,0.1h-6.6c-0.1,0-0.3,0-0.3-0.1
c0,0-0.1-0.1,0.1-0.3c0.1-0.1,0.2-0.2,0.3-0.3c0.3-0.1,0.7-0.4,1.1-0.8c0.4-0.4,0.5-0.8,0.6-1.3l0.5-14.9c0-0.5-0.1-0.9-0.5-1.3
c-0.3-0.4-0.7-0.7-1-0.9c-0.2-0.1-0.4-0.3-0.3-0.5c0-0.1,0.1-0.2,0.3-0.2h6.6c0.2,0,0.3,0.1,0.3,0.2c0,0.2-0.1,0.4-0.4,0.5
c-0.4,0.2-0.7,0.5-1,0.9c-0.3,0.4-0.5,0.9-0.5,1.3l-0.2,5.7c0,0.1,0,0.1,0.1,0.1c0,0,0.1,0.1,0.1,0.1H94c0.1,0,0.1,0,0.1-0.1
s0.1-0.1,0.1-0.1l-0.4-5.7c0-0.5-0.2-0.9-0.6-1.3c-0.3-0.4-0.7-0.7-1.1-0.9c-0.3-0.1-0.4-0.4-0.4-0.5c0-0.1,0.1-0.2,0.3-0.2h6.6
c0.2,0,0.3,0.1,0.3,0.2c0,0.2-0.1,0.4-0.3,0.5c-0.3,0.2-0.7,0.5-1,0.9c-0.3,0.4-0.5,0.9-0.4,1.3l1,14.9c0,0.5,0.2,0.9,0.6,1.3
c0.4,0.4,0.7,0.7,1.1,0.8c0.1,0.1,0.2,0.1,0.3,0.3c0.1,0.2,0.1,0.3,0.1,0.3c0,0-0.1,0.1-0.3,0.1H93.5z"/>
</g>
<g>
<path class="st2" d="M26.4,44.3c-0.8,0-1.5-0.2-2.1-0.7c-1-0.7-1.5-1.8-1.6-3.1c-0.1-1,0-1.8,0.4-2.3c0.5-0.8,1.1-1.1,1.7-1.1
c0.4,0,0.7,0.1,1.1,0.4c0.3,0.2,0.5,0.5,0.7,0.9c0.2,0.4,0.3,0.9,0.2,1.3c-0.1,0.5-0.3,0.9-0.7,1.3c-0.4,0.4-0.5,0.8-0.3,1.3
c0.1,0.4,0.4,0.5,0.8,0.5c0,0,0.1,0,0.1,0c0.5,0,1-0.3,1.3-0.7c0.2-0.2,0.4-0.7,0.7-1.4c0.3-0.7,0.5-1.5,0.7-2.5
c0.3-1.5,0.5-3.3,0.6-5.3c0.1-2,0.1-4.1-0.1-6.2c-0.1-0.5-0.3-0.9-0.7-1.4c-0.4-0.5-0.9-0.8-1.5-1c-0.3-0.1-0.4-0.2-0.4-0.5
c0-0.1,0.1-0.2,0.3-0.2h14.1c0.2,0,0.3,0.1,0.3,0.2c0,0.2-0.1,0.4-0.4,0.5c-0.3,0.2-0.7,0.5-1,0.9c-0.3,0.4-0.5,0.9-0.5,1.3
v14.9c0,0.5,0.2,0.9,0.5,1.3c0.3,0.4,0.7,0.7,1,0.8c0.1,0.1,0.2,0.1,0.3,0.3c0.1,0.2,0.1,0.3,0.1,0.3c0,0-0.1,0.1-0.3,0.1h-6.6
c-0.2,0-0.3,0-0.3-0.1c0-0.1,0-0.2,0-0.3c0-0.1,0.2-0.2,0.3-0.3c0.4-0.2,0.7-0.4,1-0.8c0.3-0.4,0.5-0.8,0.5-1.3V27
c0-0.4-0.2-0.9-0.5-1.6c-0.3-0.6-0.9-0.9-1.9-0.9c-1,0-1.6,0.3-2,0.8c-0.4,0.5-0.6,1.1-0.6,1.8c-0.2,2.4-0.4,4.9-0.6,7.4
c-0.2,2.6-0.7,4.7-1.4,6.5c-0.8,2-1.8,3.1-2.9,3.2C26.8,44.2,26.6,44.3,26.4,44.3z"/>
</g>
<g>
<path class="st2" d="M122.3,52.4c-0.1,0-0.1,0-0.2,0c-1.6-0.2-2.9-0.7-4-1.5c-1.1-0.8-1.9-1.7-2.5-2.5c-0.5-0.8-1-1.9-1.4-3.2
c-0.2-0.7-0.5-1.4-0.6-2.1c-0.2-0.7-0.4-1.4-0.6-2.1c-0.2-0.9-0.5-1.7-0.7-2.4c-0.2-0.8-0.5-1.4-0.9-1.9
c-0.5-0.5-0.9-0.9-1.4-1.1c0,0,0,0-0.1,0c0,0,0,0-0.1,0c-0.8,0.3-1.6,0.5-2.4,0.6c-0.1,0-0.2,0.1-0.2,0.2v5
c0,0.5,0.2,0.9,0.5,1.3c0.3,0.4,0.7,0.7,1,0.8c0.1,0.1,0.2,0.1,0.3,0.3c0,0.1,0.1,0.2,0,0.3c0,0-0.1,0.1-0.3,0.1h-6.6
c-0.1,0-0.2,0-0.3-0.1c0-0.1,0-0.2,0-0.3c0.1-0.1,0.2-0.2,0.3-0.3c0.4-0.2,0.7-0.4,1-0.8c0.3-0.4,0.5-0.8,0.5-1.3V26.5
c0-0.5-0.2-0.9-0.5-1.3c-0.3-0.4-0.7-0.7-1-0.9c-0.2-0.1-0.4-0.3-0.3-0.5c0-0.1,0.1-0.2,0.3-0.2h6.6c0.2,0,0.3,0.1,0.3,0.2
c0,0.2-0.1,0.4-0.4,0.5c-0.4,0.1-0.7,0.4-1,0.9c-0.3,0.4-0.5,0.9-0.5,1.3V35c0,0.1,0,0.1,0.1,0.1c0,0,0.1,0,0.1,0c0,0,0,0,0,0
c0.8-0.1,1.6-0.3,2.4-0.5c0.9-0.3,1.7-0.6,2.5-1.1c0.4-0.3,0.9-0.6,1.3-1c0.5-0.4,0.8-0.9,1.1-1.4c0.3-0.8,0.4-1.5,0.3-2.1
c-0.1-0.5-0.3-0.9-0.6-1.4c-0.3-0.5-0.4-0.9-0.5-1.2c0-0.2-0.1-0.5-0.1-0.9c0-0.4,0-0.7,0.1-1c0.4-1.1,1.1-1.6,2.1-1.6l0.2,0
c0.7,0.1,1.3,0.4,1.8,1.1c0.5,0.8,0.7,1.7,0.5,2.8c-0.2,1.1-0.5,2-0.8,2.7c-0.4,0.9-1,1.7-1.6,2.5c-0.7,0.8-1.3,1.3-1.9,1.7
c-0.5,0.3-0.9,0.6-1.4,0.8c-0.1,0-0.1,0.1-0.1,0.2c0,0.1,0,0.1,0.1,0.2c0.3,0.2,0.5,0.4,0.8,0.6c0.4,0.4,0.8,0.9,1.2,1.4
c0.6,0.8,1.2,1.7,1.6,2.8c0.4,1.1,0.9,2.2,1.3,3.4c0.4,1,0.7,2.1,1.1,3.2c0.4,1.1,0.8,2.1,1.5,3.1c0.7,1.1,1.6,2,2.6,2.6
c0.2,0.1,0.1,0.2,0.1,0.2c0,0.1-0.1,0.1-0.1,0.2C122.6,52.4,122.5,52.4,122.3,52.4z"/>
</g>
<g>
<path class="st2" d="M138.3,44.1c-0.2,0-0.4-0.1-0.5-0.3c0-0.1,0.2-0.3,0.4-0.4c0.4-0.2,0.8-0.7,1.2-1.3c0.3-0.6,0.4-1.3,0.3-2
l-3-12.6c0-0.1-0.1-0.2-0.2-0.2h-8.1c-0.1,0-0.2,0.1-0.2,0.2c-0.3,1.4-0.5,2.7-0.7,4c-0.2,1.5-0.4,2.9-0.5,4.4
c-0.1,1.4-0.1,2.8,0.1,4.1c0.1,0.8,0.3,1.5,0.5,2.1s0.7,1.1,1.3,1.4c0.4,0.3,0.4,0.3,0.4,0.4c0,0.1,0,0.3-0.4,0.3h-7.6
c-0.3,0-0.5,0-0.5-0.2c0,0,0-0.1,0-0.2c0.1-0.2,0.2-0.3,0.2-0.3c0.8-1.3,1.4-2.5,1.9-3.6c0.6-1.4,1.1-2.8,1.6-4.3
c0.5-1.5,0.9-3,1.3-4.6c0.4-1.4,0.7-2.9,1-4.3c0.3-1.4,0.7-2.9,1-4.3c0.4-2,0.9-3.9,1.3-5.8c0-0.1,0-0.1-0.1-0.2
c0,0-0.1-0.1-0.1-0.1c0,0,0,0,0,0c-0.6,0.1-1.2,0.3-1.7,0.6c-0.7,0.3-1.2,0.8-1.6,1.3c-0.1,0.1-0.2,0.2-0.4,0.3
c-0.1,0.1-0.2,0.1-0.3,0.1c-0.1,0-0.3-0.1-0.4-0.2c-0.2-0.3-0.2-0.5-0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.5c0.7-1.6,1.7-2.8,2.9-3.5
c1.3-0.7,2.6-1.1,3.9-1.1l0.2,0c1.6,0,3.1,0.3,4.4,0.9c1.4,0.7,2.4,2,2.9,4l5.1,21.7c0.2,0.7,0.4,1.4,0.8,2
c0.4,0.6,1,1.2,1.9,1.8c0.3,0.1,0.5,0.4,0.5,0.6c0,0.2,0,0.2-0.1,0.3c-0.1,0.1-0.2,0.1-0.3,0.1H138.3z M130.9,16.2
c-0.1,0-0.2,0.1-0.2,0.2c-0.3,1.4-0.6,2.8-1,4.3c-0.4,1.5-0.7,3-1.1,4.6c0,0.1,0,0.1,0,0.2s0.1,0.1,0.2,0.1h7.1
c0.1,0,0.1,0,0.2-0.1c0,0,0.1-0.1,0-0.2l-1.1-4.6c-0.6-2.6-1.9-4.1-3.8-4.4C131.2,16.2,131.1,16.2,130.9,16.2
C130.9,16.2,130.9,16.2,130.9,16.2z"/>
</g>
</g>
<g>
<path class="st3" d="M23.1,17.4c-0.1-1.6-0.6-2.9-1.3-4c-0.3-0.4-0.7-0.8-1.2-1.2c-1-0.8-2.2-0.8-3.1-0.1
c-0.8,0.6-1.1,1.3-1.1,2.3c0,0.4,0.1,0.8,0.2,1.1c0.1,0.4,0.3,0.8,0.6,1.2l0,0.1c0.2,0.4,0.4,0.8,0.6,1.1c0.5,0.9,0.9,1.9,1.3,3
c0.4,1.1,0.7,2.2,0.8,3.3c0.2,1.6,0.2,3.1-0.1,4.4c-0.2,1.3-0.6,2.5-1,3.5l0,0.1c-0.1,0.2-0.2,0.4-0.3,0.6
c-0.1,0.2-0.1,0.3-0.2,0.5c-1.4-0.9-2.6-2-3.6-3.1c-2.3-2.5-4.1-5.6-5.4-9.1c-0.2-0.6-0.4-1.2-0.5-2c-0.1-0.4-0.1-0.8-0.2-1.2
c0-0.4,0-0.8,0-1.2c0.1-1,0.6-1.8,1.5-2.2c0.3-0.2,0.6-0.3,0.6-0.6c0-0.3-0.3-0.5-0.6-0.5H1.6C1.2,13.4,1,13.7,1,14
c0,0.2,0.2,0.4,0.5,0.6c0.4,0.2,0.8,0.6,1.2,1.1c0.4,0.5,0.6,1.1,0.8,1.8c0.4,1.8,0.9,3.7,1.6,5.7c0.7,1.9,1.5,3.7,2.3,5.4
c1.3,2.5,2.7,4.5,4.2,5.9c1.4,1.3,3,2.4,4.6,3.4c-0.4,0.6-0.9,1.2-1.4,1.7c-0.6,0.6-1.2,1-1.9,1.4c-0.9,0.4-1.9,0.6-3,0.4
c-0.5-0.1-1.1-0.2-1.6-0.5c-0.5-0.2-1-0.5-1.5-0.6c-0.3-0.2-0.6-0.4-1-0.6c-0.4-0.2-0.8-0.3-1.2-0.3l0,0l-0.2,0
c-1.5,0-2.4,0.7-2.8,2c-0.3,0.9-0.2,2.2,1.5,3.1c0.5,0.3,1.1,0.5,1.7,0.5C5.5,45,6.3,45.1,7,45.1c0.1,0,0.2,0,0.4,0
c2.3,0,4.6-0.8,6.7-2.4c1.3-1,2.5-2.3,3.5-3.8c1-1.5,1.9-3,2.6-4.3c0.7-1.4,1.3-3.3,1.8-5.5c0.5-2.2,0.9-4.5,1.1-6.9
C23.2,20.6,23.2,19,23.1,17.4L23.1,17.4z"/>
<path class="st3" d="M61.3,40.1c0.2-0.9,0.2-1.8-0.2-2.6c-0.4-0.8-0.9-1.4-1.7-2c-0.8-0.5-1.6-0.9-2.4-1.2
c-0.6-0.2-1.3-0.4-1.9-0.6c-0.6-0.2-1.2-0.4-1.7-0.7c-0.4-0.2-0.8-0.5-0.9-0.8c-0.2-0.4-0.3-0.6-0.3-0.7c0-0.5,0.2-0.6,0.2-0.6
c0.4-0.1,0.7-0.3,1-0.7c0.3-0.4,0.5-0.8,0.5-1.3c0-0.9-0.5-1.4-1.4-1.4c-0.7,0-1.2,0.3-1.6,0.8c-0.2,0.3-0.4,0.7-0.4,1
c-0.1,0.4-0.1,0.7-0.1,0.9c0,1.4,0.5,2.4,1.6,3c0.4,0.3,1,0.7,1.9,1.1c0.8,0.4,1.4,0.7,1.8,1c0.5,0.4,0.9,0.9,1.1,1.6
c0.2,0.7,0.3,1.3,0.3,2c-0.1,1.5-0.6,2.6-1.6,3.3c-0.6,0.5-1.6,0.7-2.9,0.7c-0.1,0-0.3,0-0.4,0c-0.7,0-1.3-0.2-1.8-0.7
c-0.5-0.4-0.8-1.1-0.8-2.1l0-14c0-0.4,0.1-0.8,0.5-1.2c0.3-0.4,0.6-0.7,1-0.8c0.4-0.2,0.5-0.5,0.5-0.7c0-0.1-0.1-0.4-0.5-0.4
h-6.6c-0.4,0-0.5,0.2-0.5,0.4c0,0.2,0,0.5,0.5,0.7c0.3,0.1,0.6,0.4,0.9,0.8c0.3,0.4,0.4,0.8,0.4,1.2v14.9c0,0.4-0.1,0.8-0.4,1.1
c-0.3,0.4-0.6,0.6-1,0.8c-0.2,0.1-0.3,0.2-0.4,0.4c-0.1,0.2-0.1,0.4,0,0.5c0.1,0.1,0.2,0.2,0.5,0.2h4.4v0l4.6,0
c1.4,0,2.7-0.1,3.8-0.3c1.2-0.2,2.2-0.7,2.9-1.6C60.7,41.8,61.1,41,61.3,40.1L61.3,40.1z"/>
<path class="st3" d="M79,43.2c-0.3-0.1-0.7-0.4-1-0.7c-0.3-0.3-0.4-0.7-0.4-1.2V28.1c0-0.4,0.2-0.8,0.5-1.2
c0.3-0.4,0.6-0.7,1-0.9c0.4-0.2,0.5-0.5,0.5-0.7c-0.1-0.3-0.3-0.4-0.5-0.4c-1.4-0.2-2.6-0.5-3.6-0.9c-1-0.4-2.2-0.7-3.4-0.9
c-0.7-0.1-1.4-0.2-2.1-0.2c-0.7,0-1.5-0.1-2.2,0c-1.4,0.1-2.7,0.3-3.7,0.8c-1.6,0.7-2.6,1.7-3.1,3c-0.5,1.4-0.3,2.9,0.5,4.4
c0.3,0.6,0.8,1.2,1.3,1.6c0.5,0.4,1.1,0.8,1.6,1.1c0.6,0.3,1.3,0.6,2,0.7c0.4,0.1,0.9,0.2,1.3,0.3c-0.6,0.4-1.2,1-1.8,1.8
c-0.6,0.8-1.2,1.8-1.5,2.9c-0.4,1.1-0.8,2.3-1.1,3.4c-0.2,0.8-0.6,1.9-0.9,3.2c-0.4,1.3-0.8,2.6-1.4,3.8
c-0.6,1.3-1.3,2.3-1.9,2.7c-0.2,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.2,0.3,0.3c0.1,0,0.3,0.1,0.4,0.1c0.1,0,0.2,0,0.3,0
c1.6-0.3,3-1,4-2.2c1-1.2,1.8-2.2,2.3-3.1l0.8-1.4c0.3-0.5,0.5-1,0.7-1.6c0.2-0.7,0.4-1.4,0.5-2.2c0.2-0.7,0.3-1.4,0.5-2.1
C68.7,40,69,39,69.4,38c0.3-1,0.7-1.8,1.1-2.3c0.2-0.3,0.4-0.4,0.7-0.5c0.2,0,0.5,0,0.7,0l1.4,0.1c0.1,0,0.3,0,0.4,0v5.8
c0,0.4-0.1,0.8-0.4,1.2c-0.3,0.4-0.6,0.6-0.9,0.7c-0.2,0.1-0.4,0.2-0.4,0.4c-0.1,0.2,0,0.4,0,0.5c0.1,0.1,0.2,0.2,0.5,0.2h6.6
c0.2,0,0.4-0.1,0.5-0.2c0.1-0.1,0.1-0.3-0.1-0.6C79.2,43.4,79.1,43.3,79,43.2L79,43.2z M73.6,25.5v8.4c-0.5,0-1,0-1.5,0l-0.2,0
c-0.5,0-1,0-1.5-0.1c-1.2-0.2-2.2-0.5-2.9-1c-0.9-0.5-1.5-1.3-1.8-2.3c-0.3-0.9-0.3-1.7,0-2.6c0.3-0.8,0.8-1.5,1.6-2.1
c0.6-0.5,1.4-0.8,2.1-1c0.2,0,0.4,0,0.6,0c0.1,0,0.3,0,0.4,0c0.4,0,0.8,0.1,1.3,0.1c0.3,0,0.6,0.1,0.9,0.1c0.3,0,0.5,0.1,0.7,0.2
C73.6,25.3,73.6,25.4,73.6,25.5L73.6,25.5z"/>
<path class="st3" d="M100.1,43.2c-0.3-0.1-0.7-0.4-1-0.8c-0.3-0.3-0.5-0.7-0.5-1.1l-1-14.9c0-0.4,0.1-0.8,0.4-1.2
c0.3-0.4,0.6-0.7,0.9-0.8c0.3-0.1,0.5-0.4,0.4-0.8c0-0.1-0.1-0.4-0.5-0.4h-6.6c-0.4,0-0.5,0.3-0.5,0.4c0,0.2,0.1,0.5,0.5,0.7
c0.3,0.1,0.7,0.4,1,0.8c0.3,0.4,0.5,0.8,0.5,1.2l0.4,5.7h-7.2l0.2-5.7c0-0.4,0.2-0.8,0.5-1.2c0.3-0.4,0.6-0.7,1-0.8
c0.5-0.2,0.5-0.5,0.5-0.8c0-0.1-0.1-0.4-0.5-0.4h-6.6c-0.4,0-0.5,0.2-0.5,0.4c0,0.3,0.1,0.6,0.4,0.7c0.3,0.1,0.6,0.4,0.9,0.8
c0.3,0.4,0.4,0.8,0.4,1.2l-0.5,14.9c0,0.4-0.2,0.8-0.5,1.1c-0.3,0.4-0.7,0.6-1,0.8c-0.1,0.1-0.3,0.2-0.4,0.3
c-0.1,0.2-0.2,0.4-0.1,0.5c0.1,0.2,0.4,0.2,0.5,0.2h6.6c0.2,0,0.4-0.1,0.5-0.2c0.1-0.1,0.1-0.2,0-0.5c-0.1-0.2-0.2-0.3-0.4-0.4
c-0.3-0.1-0.6-0.4-0.9-0.7c-0.3-0.3-0.4-0.7-0.4-1.1l0.2-7.6h7.4l0.5,7.6c0,0.4-0.1,0.8-0.4,1.1c-0.3,0.4-0.6,0.6-0.9,0.7
c-0.2,0.1-0.3,0.2-0.4,0.4c-0.1,0.2,0,0.4,0,0.5c0.1,0.1,0.2,0.2,0.5,0.2h6.6c0.2,0,0.4-0.1,0.5-0.2c0.1-0.1,0.1-0.3-0.1-0.5
C100.4,43.4,100.2,43.3,100.1,43.2L100.1,43.2z"/>
<path class="st3" d="M41.9,43.2c-0.3-0.1-0.6-0.4-1-0.8c-0.3-0.3-0.5-0.7-0.5-1.1V26.5c0-0.4,0.2-0.8,0.5-1.2
c0.3-0.4,0.6-0.7,0.9-0.8c0.3-0.1,0.5-0.4,0.5-0.7c0-0.1-0.1-0.4-0.5-0.4H27.8c-0.4,0-0.5,0.2-0.5,0.4c0,0.4,0.1,0.6,0.5,0.7
c0.6,0.2,1,0.5,1.4,0.9c0.4,0.5,0.6,0.9,0.7,1.3c0.2,2.1,0.2,4.2,0.1,6.2c-0.1,2-0.3,3.8-0.6,5.3c-0.2,0.9-0.5,1.8-0.7,2.4
c-0.3,0.7-0.5,1.1-0.7,1.3c-0.3,0.4-0.7,0.6-1.1,0.6c-0.5,0-0.7-0.2-0.7-0.4c-0.1-0.4,0-0.8,0.3-1.1c0.4-0.4,0.7-0.9,0.8-1.4
c0.1-0.5,0-1-0.2-1.5c-0.2-0.4-0.5-0.7-0.8-0.9c-1.2-0.7-2.3-0.4-3.1,0.8c-0.4,0.5-0.5,1.3-0.4,2.4c0.1,1.4,0.6,2.5,1.7,3.3
c0.6,0.5,1.4,0.7,2.2,0.7c0.2,0,0.3,0,0.5,0c1.3-0.1,2.3-1.2,3.1-3.3c0.7-1.7,1.1-3.9,1.4-6.5c0.2-2.6,0.4-5,0.6-7.4
c0-0.6,0.2-1.2,0.6-1.7c0.3-0.5,0.9-0.7,1.8-0.7c0.9,0,1.4,0.3,1.7,0.8c0.3,0.6,0.5,1.1,0.5,1.5v14.3c0,0.4-0.1,0.8-0.4,1.1
c-0.3,0.4-0.6,0.6-1,0.8c-0.2,0.1-0.3,0.3-0.4,0.4c-0.1,0.2-0.1,0.4,0,0.5c0.1,0.1,0.2,0.2,0.5,0.2h6.6c0.2,0,0.4-0.1,0.5-0.2
c0.1-0.1,0.1-0.3-0.1-0.5C42.2,43.4,42.1,43.3,41.9,43.2L41.9,43.2z"/>
<path class="st3" d="M122.8,51.8c-1-0.6-1.8-1.5-2.5-2.6c-0.6-0.9-1.1-1.9-1.4-3c-0.4-1.1-0.7-2.2-1.1-3.2
c-0.4-1.2-0.8-2.3-1.3-3.4c-0.4-1.1-1-2.1-1.6-2.8c-0.5-0.5-0.9-1-1.3-1.4c-0.3-0.3-0.5-0.5-0.8-0.7c0.5-0.3,1-0.5,1.4-0.8
c0.6-0.4,1.3-1,2-1.8c0.7-0.8,1.2-1.6,1.6-2.5c0.3-0.8,0.6-1.7,0.8-2.8c0.2-1.1,0-2.1-0.5-2.9c-0.5-0.7-1.1-1.1-1.9-1.2
c-1.2-0.1-2,0.5-2.5,1.8c-0.1,0.3-0.1,0.6-0.1,1c0,0.4,0.1,0.7,0.1,0.9c0,0.4,0.2,0.8,0.5,1.3c0.3,0.4,0.5,0.9,0.6,1.3
c0.2,0.6,0.1,1.3-0.2,2c-0.2,0.5-0.6,1-1,1.4c-0.5,0.4-0.9,0.7-1.3,1c-0.8,0.5-1.6,0.9-2.5,1.1c-0.8,0.2-1.6,0.4-2.3,0.5v-8.5
c0-0.4,0.2-0.8,0.5-1.2c0.3-0.4,0.6-0.7,1-0.8c0.5-0.2,0.5-0.5,0.5-0.7c0-0.1-0.1-0.4-0.5-0.4h-6.6c-0.4,0-0.5,0.2-0.5,0.4
c0,0.2,0,0.5,0.5,0.7c0.3,0.1,0.6,0.4,0.9,0.8c0.3,0.4,0.4,0.8,0.4,1.2v14.9c0,0.4-0.1,0.8-0.4,1.1c-0.3,0.4-0.6,0.6-1,0.8
c-0.2,0.1-0.3,0.2-0.4,0.4c-0.1,0.2-0.1,0.4,0,0.4c0.1,0.2,0.4,0.2,0.5,0.2h6.6c0.2,0,0.4-0.1,0.5-0.2c0.1-0.1,0.1-0.3,0-0.5
c-0.1-0.1-0.2-0.3-0.4-0.3c-0.3-0.1-0.7-0.4-1-0.7c-0.3-0.3-0.5-0.7-0.5-1.1v-5c0.8-0.1,1.6-0.4,2.4-0.6c0.4,0.2,0.9,0.5,1.3,1
c0.4,0.5,0.7,1.1,0.9,1.8c0.2,0.8,0.4,1.6,0.7,2.4c0.2,0.7,0.4,1.3,0.6,2.1c0.2,0.7,0.4,1.5,0.7,2.1c0.4,1.3,0.9,2.4,1.5,3.2
c0.6,0.9,1.4,1.8,2.5,2.6c1.1,0.8,2.5,1.4,4.1,1.6c0.1,0,0.2,0,0.2,0c0.2,0,0.3,0,0.4-0.1c0.2-0.1,0.3-0.2,0.3-0.3
C123.1,52,123,51.9,122.8,51.8L122.8,51.8z"/>
<path class="st3" d="M146.9,42.9c-0.8-0.6-1.5-1.2-1.8-1.8c-0.4-0.6-0.6-1.2-0.8-1.9l-5.1-21.7c-0.5-2.1-1.5-3.5-3-4.2
c-1.4-0.6-2.9-1-4.5-1l-0.2,0c-1.4,0-2.7,0.4-4,1.2c-1.3,0.7-2.3,1.9-3,3.6c-0.1,0.1-0.1,0.3-0.2,0.5c-0.1,0.2-0.1,0.5,0.2,0.8
c0.2,0.3,0.4,0.3,0.5,0.3c0.1,0,0.3,0,0.4-0.1c0.3-0.2,0.4-0.3,0.4-0.4c0.4-0.5,0.9-0.9,1.5-1.2c0.5-0.3,1.1-0.4,1.6-0.6
c-0.4,1.9-0.9,3.8-1.3,5.8c-0.3,1.5-0.7,2.9-1,4.3c-0.3,1.5-0.7,2.9-1,4.3c-0.4,1.6-0.9,3.1-1.3,4.6c-0.5,1.4-1,2.9-1.6,4.2
c-0.5,1.1-1.1,2.3-1.9,3.6c0,0.1-0.1,0.2-0.2,0.3c-0.1,0.2-0.1,0.4,0,0.4c0.1,0.2,0.4,0.3,0.7,0.3h7.6c0.4,0,0.6-0.3,0.6-0.5
c0-0.2-0.1-0.2-0.5-0.6c-0.6-0.3-1-0.7-1.2-1.3c-0.2-0.6-0.4-1.3-0.5-2c-0.2-1.3-0.2-2.6-0.1-4c0.1-1.4,0.3-2.9,0.5-4.4
c0.2-1.3,0.4-2.6,0.7-4h8.1l3,12.6c0.1,0.7,0.1,1.3-0.3,1.8c-0.3,0.6-0.7,1-1.1,1.2c-0.4,0.3-0.6,0.4-0.5,0.6
c0.1,0.3,0.3,0.5,0.7,0.5h8.7c0.2,0,0.4-0.1,0.5-0.2c0.1-0.1,0.1-0.2,0.1-0.4C147.5,43.3,147.3,43.1,146.9,42.9L146.9,42.9z
M135.9,25.3h-7.1c0.3-1.5,0.7-3.1,1.1-4.6c0.4-1.5,0.7-3,1-4.4c0.1,0,0.2,0,0.3,0c1.8,0.3,3,1.7,3.6,4.3L135.9,25.3L135.9,25.3z
"/>
</g>
<g>
<g>
<path class="st2" d="M58.4,16.6c-0.4,0-0.6-0.1-0.8-0.2c-0.2-0.1-0.4-0.3-0.5-0.5c-0.1-0.2-0.2-0.4-0.2-0.7c0-0.3,0-0.6,0-0.8
c0-0.2,0-0.5,0.1-0.8c0.1-0.3,0.1-0.7,0.2-1c0.1-0.4,0.2-0.8,0.3-1.2c0.1-0.4,0.2-0.8,0.4-1.2c0-0.1,0-0.2,0-0.3
c0.1,0,0.2-0.1,0.2-0.2c0.2-0.4,0.4-0.9,0.6-1.4c0.2-0.5,0.4-1,0.7-1.5c0.2-0.5,0.4-0.9,0.7-1.3c0.2-0.4,0.4-0.7,0.6-1
c0.2-0.2,0.3-0.5,0.5-0.7c-0.2,0.4-0.4,0.8-0.6,1.2c-0.4,0.9-0.9,2-1.3,3.1c-0.1,0.2,0,0.3,0.1,0.5L59,8.7c0,0-0.1,0.1-0.1,0.2
c-0.1,0.3-0.2,0.5-0.3,0.8c-0.1,0.2-0.1,0.4-0.2,0.6c-0.1,0.2-0.2,0.4-0.2,0.5c0,0.1,0,0.3,0.1,0.4c0.1,0.1,0.2,0.2,0.3,0.2
c0,0,0.1,0,0.2,0c0,0,0,0,0,0c-0.2,0.5-0.3,1.1-0.3,1.7c0,0.5,0.1,0.9,0.2,1.2c0.1,0.2,0.1,0.3,0.2,0.5
c-0.1-0.1-0.2-0.3-0.3-0.4c-0.1-0.2-0.2-0.2-0.4-0.2c0,0-0.1,0-0.1,0l-0.1,0c-0.2,0.1-0.3,0.2-0.3,0.4c0,0.6,0.1,1.1,0.4,1.5
c0.3,0.3,0.6,0.5,0.9,0.6C58.8,16.6,58.6,16.6,58.4,16.6z M60.6,15.7C60.6,15.7,60.7,15.7,60.6,15.7
C60.6,15.7,60.6,15.7,60.6,15.7C60.6,15.7,60.6,15.7,60.6,15.7z M61.9,14.5c0.1-0.2,0.2-0.4,0.3-0.5c0.2-0.3,0.3-0.7,0.4-1
c0.1-0.3,0.2-0.7,0.2-0.9c0-0.3,0.1-0.5,0.1-0.7c0-0.7-0.1-1.2-0.3-1.5c-0.2-0.2-0.5-0.5-1.1-0.5c0.1,0,0.2-0.1,0.2-0.1
C62,9.1,62.2,9,62.4,9c0.5,0,0.9,0.1,1,0.4c0.2,0.3,0.3,0.7,0.3,1.2c0,0.3,0,0.6-0.1,0.9c-0.1,0.4-0.2,0.8-0.4,1.2
c-0.2,0.4-0.4,0.8-0.7,1.2C62.3,14.1,62.1,14.3,61.9,14.5z M65.1,2.8c0.1-0.3,0.2-0.7,0.2-1c0-0.4-0.1-0.7-0.2-0.9
c-0.1-0.2-0.3-0.3-0.6-0.3c0.3-0.1,0.6-0.2,0.8-0.2c0.3,0,0.4,0,0.4,0.1c0.1,0,0.1,0.1,0.1,0.1c0,0.1,0,0.1,0.1,0.2
c0,0.1,0,0.2,0,0.3c0,0.1,0,0.3-0.2,0.7C65.6,2.1,65.4,2.5,65.1,2.8C65.1,2.9,65.1,2.8,65.1,2.8z"/>
</g>
<g>
<path class="st2" d="M67.2,16.3c-0.2,0-0.4,0-0.6-0.1c-0.2-0.1-0.3-0.2-0.5-0.3c-0.1-0.1-0.3-0.3-0.4-0.6
c-0.1-0.3-0.1-0.6-0.1-0.9c0-0.4,0-0.7,0.1-1c0.1-0.3,0.2-0.7,0.3-1.1c0.1-0.3,0.2-0.7,0.3-1c0.1-0.3,0.3-0.6,0.4-0.9
c0.1-0.3,0.3-0.5,0.4-0.7c0.1-0.2,0.2-0.4,0.4-0.5c0.1-0.1,0.2-0.1,0.3-0.2c0.1,0,0.2-0.1,0.3-0.1c0.1,0,0.1,0,0.1,0
c0,0,0,0,0.1,0.1C68.4,9,68.4,9,68.5,9.1c-0.2,0.2-0.3,0.5-0.5,0.8c-0.2,0.3-0.3,0.7-0.4,1.2c-0.1,0.2-0.1,0.5-0.2,0.8
c-0.1-0.1-0.2-0.1-0.3-0.1c-0.2,0-0.4,0.1-0.5,0.3c0,0.1-0.1,0.3-0.2,0.5c-0.1,0.3-0.1,0.6-0.1,1.2c0,0.5,0,0.9,0.1,1.2
c0.1,0.3,0.3,0.6,0.4,0.8c0.2,0.2,0.4,0.3,0.6,0.4c0.2,0.1,0.3,0.1,0.5,0.1h0C67.8,16.3,67.5,16.3,67.2,16.3z M68.5,16.1
c0,0,0.1-0.1,0.1-0.2c0-0.1,0-0.2,0-0.3c0.2,0.1,0.3,0.2,0.5,0.2c0,0,0,0,0,0C68.9,15.9,68.7,16,68.5,16.1z M69.8,15.8
c-0.1,0-0.2,0-0.2,0c0,0,0.1-0.1,0.2-0.1C69.8,15.8,69.8,15.8,69.8,15.8z M71.6,13.7c0.1-0.2,0.2-0.3,0.3-0.5
c0.3-0.5,0.5-1.1,0.6-1.7c0.1-0.6,0.2-1.1,0.2-1.6c0-0.6-0.1-1.1-0.4-1.5c-0.2-0.3-0.6-0.7-1.5-0.7c-0.1,0-0.3,0-0.5,0.1
c0.2-0.1,0.5-0.3,0.8-0.3c0.3-0.1,0.6-0.1,1-0.1c0.4,0,0.8,0.1,1,0.4c0.3,0.3,0.4,0.8,0.4,1.5c0,0.5-0.1,1-0.3,1.6
c-0.2,0.6-0.4,1.1-0.8,1.7C72.3,12.9,72,13.3,71.6,13.7z"/>
</g>
<g>
<path class="st2" d="M76.2,16.3c-0.3,0-0.4-0.1-0.5-0.3c-0.1-0.3-0.2-0.7-0.2-1.2c0-0.4,0-0.7,0.1-1.2c0.1-0.5,0.2-0.9,0.4-1.3
c0.2-0.4,0.3-0.8,0.5-1.2c0.2-0.4,0.3-0.6,0.4-0.7c0.1-0.2,0.2-0.3,0.3-0.5c0,0,0,0,0,0c-0.1,0.4-0.3,0.7-0.4,1.1
c-0.1,0.4-0.2,0.6-0.2,0.8c0,0.1,0,0.3,0.2,0.4c-0.1,0.1-0.1,0.2-0.2,0.3c0,0.1-0.1,0.1-0.1,0.2l0,0.4c0,0.1,0,0.2,0,0.4
c0,0.1,0,0.2,0,0.3c0,0.3,0,0.5,0,0.7c0,0.2,0,0.4,0.1,0.6c0.1,0.2,0.2,0.4,0.4,0.5c0.2,0.1,0.4,0.2,0.7,0.2c0,0,0,0,0.1,0
c-0.2,0.1-0.4,0.2-0.6,0.3C76.7,16.3,76.4,16.3,76.2,16.3z M81.1,10.6c0.1-0.4,0.2-0.7,0.2-1.1c0.1-0.5,0.1-0.9,0.2-1.3
c0-0.4,0-0.7,0-0.9c0-1-0.1-1.9-0.2-2.6c-0.2-0.7-0.4-1.3-0.6-1.8c-0.3-0.5-0.6-0.8-1-1c-0.4-0.2-0.8-0.3-1.2-0.3
c-0.2,0-0.4,0-0.6,0c-0.1,0-0.2,0-0.2,0c0.2-0.1,0.4-0.2,0.6-0.3c0.3-0.1,0.5-0.1,0.8-0.1c0.4,0,0.8,0.1,1.2,0.2
C80.7,1.7,81,2,81.2,2.4c0.3,0.4,0.5,0.9,0.7,1.5c0.2,0.6,0.2,1.4,0.2,2.4c0,0.4,0,0.8-0.1,1.3c-0.1,0.5-0.2,1-0.4,1.6
C81.5,9.6,81.3,10.1,81.1,10.6z M78.8,8.6c-0.1-0.1-0.2-0.2-0.4-0.2c0.2-0.2,0.3-0.3,0.4-0.3c0,0.1,0,0.1,0,0.2
C78.8,8.4,78.8,8.5,78.8,8.6z"/>
</g>
<g>
<path class="st2" d="M88.1,16.6c-0.1,0-0.1,0-0.1-0.1c-0.1-0.1-0.1-0.3-0.1-0.4c0-0.1,0-0.3,0-0.5c0-0.2,0-0.4,0.1-0.6
c0-0.2,0.1-0.4,0.1-0.5c0-0.2,0.1-0.3,0.1-0.4c0-0.1,0-0.3-0.1-0.4c0-0.1-0.1-0.1-0.2-0.1c0.2-0.4,0.5-0.8,0.7-1.2
c0.2-0.5,0.4-0.9,0.5-1.3c0.1-0.4,0.2-0.7,0.4-1c0-0.1,0.1-0.2,0.2-0.4c0.1-0.1,0.2-0.3,0.3-0.4C90,9.1,90.1,9,90.2,8.9
c0.1,0,0.1-0.1,0.1-0.1c0.1,0,0.2-0.1,0.3-0.2c0.1-0.1,0.1-0.2,0.1-0.4c0-0.2-0.2-0.3-0.3-0.5c-0.1-0.1-0.3-0.2-0.4-0.3
c-0.1-0.1-0.2-0.1-0.4-0.1c0.1,0,0.1,0,0.2,0c0.1,0,0.3,0,0.5,0c0.2,0,0.3,0.1,0.5,0.2c0.2,0.1,0.3,0.2,0.4,0.3
c0.1,0.1,0.1,0.1,0.1,0.3c0,0.1,0,0.2,0,0.3c0,0,0,0.1-0.1,0.1c0,0.1-0.1,0.1-0.2,0.2c-0.1,0.1-0.2,0.2-0.3,0.3
c0,0-0.1,0.1-0.1,0.2c-0.1,0.3-0.2,0.6-0.4,0.8c-0.2,0.3-0.3,0.7-0.5,1.1c-0.3,0.9-0.6,1.7-0.8,2.3c-0.3,0.9-0.3,1.2-0.3,1.3
c0,0.4,0.1,0.7,0.2,0.9c0.2,0.2,0.4,0.3,0.6,0.3c0,0,0,0,0.1,0c-0.1,0.1-0.3,0.2-0.4,0.2C88.5,16.6,88.3,16.6,88.1,16.6z
M83.8,16.2c-0.5,0-0.6-0.2-0.7-0.3c-0.1-0.3-0.2-0.7-0.2-1.2c0-0.3,0.1-0.8,0.2-1.2c0.1-0.5,0.3-0.9,0.5-1.4
c0.2-0.5,0.4-0.9,0.7-1.3c0.3-0.4,0.6-0.8,0.9-1.2c0.1-0.1,0.3-0.3,0.4-0.4C85.4,9.5,85.2,9.7,85,10c-0.2,0.3-0.4,0.6-0.5,1
c-0.1,0.4-0.3,0.7-0.4,1.1c-0.1,0.4-0.2,0.7-0.3,1.1c-0.1,0.4-0.1,0.7-0.1,0.9c0,0.6,0.1,1,0.4,1.2c0.3,0.2,0.5,0.4,0.8,0.4
c0.1,0,0.3,0,0.4,0C84.8,16,84.2,16.2,83.8,16.2z"/>
</g>
</g>
<g>
<path class="st3" d="M66.4,1.1c0,0.2-0.1,0.5-0.2,0.9c-0.2,0.4-0.4,0.8-0.7,1.3c-0.3,0.5-0.8,1-1.4,1.6c-0.6,0.6-1.3,1.3-2.1,2
c-0.4,0.4-0.9,0.7-1.3,1.1c-0.5,0.4-0.9,0.8-1.3,1.1c-0.1,0.3-0.2,0.5-0.3,0.7c-0.1,0.2-0.1,0.4-0.2,0.6
c-0.1,0.2-0.1,0.4-0.2,0.5h0.1c0.3-0.4,0.6-0.7,0.9-1c0.3-0.3,0.7-0.5,1-0.7c0.3-0.2,0.7-0.3,1-0.4c0.3-0.1,0.6-0.1,0.8-0.1
c0.7,0,1.1,0.2,1.4,0.6c0.2,0.4,0.4,0.8,0.4,1.4c0,0.3-0.1,0.6-0.2,1c-0.1,0.4-0.3,0.8-0.5,1.2c-0.2,0.4-0.4,0.8-0.7,1.3
c-0.3,0.4-0.6,0.8-1,1.1c0.3,0,0.6-0.1,0.9-0.2c0.3-0.1,0.7-0.2,1.1-0.4c0.4-0.2,0.7-0.3,1-0.5c0.3-0.2,0.6-0.4,0.8-0.5l0,0.4
c-0.3,0.2-0.5,0.3-0.9,0.5c-0.3,0.2-0.7,0.4-1.1,0.5c-0.4,0.2-0.8,0.3-1.2,0.4c-0.4,0.1-0.8,0.2-1.2,0.2
c-0.2,0.1-0.3,0.3-0.5,0.4c-0.2,0.2-0.4,0.3-0.7,0.4c-0.2,0.1-0.5,0.2-0.8,0.3c-0.3,0.1-0.5,0.1-0.8,0.1c-0.4,0-0.8-0.1-1.1-0.3
c-0.3-0.2-0.5-0.4-0.6-0.6c-0.1-0.3-0.2-0.5-0.3-0.9c0-0.3-0.1-0.6-0.1-0.9c0-0.2,0-0.5,0.1-0.8c0.1-0.3,0.1-0.7,0.2-1.1
c0.1-0.4,0.2-0.8,0.3-1.2c0.1-0.4,0.3-0.8,0.4-1.2c-0.2,0.1-0.3,0.1-0.3-0.1c0-0.1,0.1-0.2,0.2-0.3c0.1-0.1,0.1-0.1,0.2-0.1
c0.2-0.4,0.4-0.9,0.6-1.4c0.2-0.5,0.5-1,0.7-1.5c0.2-0.5,0.5-0.9,0.7-1.3c0.2-0.4,0.4-0.8,0.6-1c1-1.5,2-2.6,2.8-3.3
c0.9-0.7,1.6-1,2.3-1c0.3,0,0.5,0,0.6,0.1c0.1,0.1,0.3,0.2,0.3,0.3c0.1,0.1,0.1,0.2,0.1,0.4C66.4,0.9,66.4,1,66.4,1.1L66.4,1.1z
M60.2,15.8c-0.6,0-1-0.1-1.3-0.3c-0.3-0.3-0.5-0.6-0.7-0.9l-0.1,0c0,0.5,0.1,0.9,0.3,1.2c0.2,0.3,0.5,0.4,0.8,0.4
c0.1,0,0.2,0,0.4-0.1c0.1,0,0.2-0.1,0.3-0.1C60,15.9,60.1,15.9,60.2,15.8L60.2,15.8z M62.5,11.3c0-0.6-0.1-1.1-0.3-1.3
c-0.2-0.2-0.5-0.4-0.8-0.4c-0.2,0-0.5,0.1-0.8,0.2c-0.3,0.1-0.6,0.3-0.8,0.6c-0.3,0.3-0.5,0.6-0.7,1.1c-0.2,0.4-0.3,1-0.3,1.6
c0,0.4,0,0.8,0.1,1.1c0.1,0.3,0.2,0.5,0.4,0.7c0.2,0.2,0.4,0.3,0.6,0.3c0.2,0.1,0.5,0.1,0.8,0.1c0.2-0.1,0.3-0.3,0.5-0.6
c0.2-0.3,0.4-0.6,0.6-0.9c0.1-0.3,0.3-0.7,0.4-1c0.1-0.3,0.2-0.6,0.2-0.9C62.5,11.6,62.5,11.4,62.5,11.3L62.5,11.3z M64.9,1.8
c0-0.3,0-0.5-0.1-0.6C64.7,1,64.5,1,64.3,1c-0.3,0-0.6,0.2-1,0.5c-0.4,0.3-0.8,0.8-1.2,1.4c-0.4,0.6-0.8,1.4-1.3,2.3
c-0.4,0.9-0.9,1.9-1.3,3.1c0.3-0.2,0.6-0.6,1.1-0.9c0.5-0.4,1-0.9,1.6-1.5C62.7,5.4,63,5,63.4,4.6c0.3-0.4,0.6-0.7,0.8-1
c0.2-0.3,0.4-0.6,0.5-0.9C64.9,2.4,64.9,2.1,64.9,1.8L64.9,1.8z"/>
<path class="st3" d="M72.8,15.6C72,16,71,16.2,70,16.2c-0.3,0-0.5,0-0.7-0.1c-0.7,0.4-1.4,0.5-2.1,0.5c-0.3,0-0.5,0-0.7-0.1
c-0.2-0.1-0.5-0.2-0.6-0.4c-0.2-0.2-0.3-0.4-0.5-0.7c-0.1-0.3-0.2-0.7-0.2-1.1c0-0.4,0-0.8,0.1-1.1c0.1-0.3,0.2-0.7,0.3-1.1
c0.1-0.3,0.2-0.7,0.3-1c0.1-0.3,0.3-0.6,0.4-0.9c0.1-0.3,0.3-0.6,0.4-0.8C67,9.2,67.1,9,67.2,8.8c0.1-0.1,0.2-0.2,0.4-0.3
c0.2-0.1,0.3-0.1,0.5-0.1c0.1,0,0.2,0,0.3,0.1c0.1,0,0.1,0.1,0.2,0.1h0.1c0.2-0.2,0.5-0.4,0.7-0.6c0.2-0.2,0.5-0.4,0.8-0.6
c0.3-0.2,0.6-0.3,0.9-0.4c0.3-0.1,0.7-0.2,1.1-0.2c0.5,0,1,0.2,1.3,0.5C73.8,7.8,74,8.4,74,9.2c0,0.5-0.1,1.1-0.3,1.7
c-0.2,0.6-0.5,1.2-0.8,1.8c-0.3,0.6-0.8,1.1-1.2,1.6c-0.5,0.5-1,0.9-1.5,1.3c0,0,0.1,0,0.2,0.1c0.1,0,0.3,0,0.5,0
c0.6,0,1.3-0.2,2-0.5c0.8-0.3,1.5-0.8,2.3-1.4l0.2,0.3C74.6,14.7,73.7,15.2,72.8,15.6L72.8,15.6z M67.5,15
c-0.2-0.3-0.3-0.7-0.3-1c-0.1-0.3-0.1-0.7-0.1-1c0-0.3,0-0.6,0.1-0.8h-0.1c0,0.1-0.1,0.3-0.2,0.5c-0.1,0.2-0.1,0.6-0.1,1.1
c0,0.4,0,0.8,0.1,1.1c0.1,0.3,0.2,0.5,0.3,0.6c0.1,0.1,0.3,0.2,0.4,0.3c0.1,0,0.3,0.1,0.3,0.1h0.2C67.9,15.6,67.6,15.3,67.5,15
L67.5,15z M72.3,9.9c0-0.5-0.1-0.9-0.3-1.3c-0.2-0.3-0.6-0.5-1.1-0.5c-0.2,0-0.4,0-0.7,0.1c-0.3,0.1-0.6,0.2-0.8,0.4
c-0.1,0.1-0.3,0.3-0.5,0.5c-0.2,0.2-0.3,0.5-0.5,0.8c-0.2,0.3-0.3,0.7-0.4,1.1c-0.1,0.4-0.2,0.9-0.2,1.4c0,0.1,0,0.3,0,0.6
c0,0.3,0.1,0.6,0.2,0.9c0.1,0.3,0.3,0.6,0.5,0.9c0.2,0.3,0.6,0.4,1,0.5c0.4-0.2,0.8-0.6,1.2-1c0.4-0.4,0.7-0.9,0.9-1.4
c0.2-0.5,0.4-1.1,0.6-1.6C72.2,10.9,72.3,10.4,72.3,9.9L72.3,9.9z"/>
<path class="st3" d="M82.5,6.3c0,0.4,0,0.9-0.1,1.4c-0.1,0.5-0.2,1.1-0.4,1.6c-0.2,0.6-0.3,1.1-0.6,1.7c-0.2,0.6-0.5,1.1-0.7,1.6
c-0.4,0.8-0.9,1.5-1.3,2.1c-0.4,0.5-0.8,1-1.2,1.3c-0.4,0.3-0.8,0.5-1.1,0.7c-0.3,0.1-0.7,0.2-1,0.2c-0.4,0-0.7-0.2-0.8-0.5
c-0.1-0.3-0.2-0.8-0.2-1.3c0-0.4,0.1-0.8,0.2-1.3c0.1-0.5,0.2-0.9,0.4-1.3c0.2-0.4,0.3-0.8,0.5-1.2c0.2-0.4,0.3-0.6,0.4-0.8
c0.5-0.8,0.9-1.5,1.4-1.9c0.4-0.5,0.7-0.7,1-0.7c0.2,0,0.3,0,0.3,0.1c0,0.1,0.1,0.3,0.1,0.5c0,0.3-0.1,0.6-0.2,1
c-0.2,0.4-0.4,0.8-0.6,1.2c-0.2,0.4-0.5,0.8-0.8,1.3c-0.3,0.4-0.5,0.8-0.7,1.1c0,0.1,0,0.3,0,0.4c0,0.1,0,0.2,0,0.3
c0,0.1,0,0.2,0,0.2c0,0.3,0,0.5,0,0.7c0,0.2,0,0.4,0.1,0.5c0,0.1,0.1,0.2,0.2,0.3c0.1,0.1,0.2,0.1,0.4,0.1c0.2,0,0.3,0,0.5-0.1
c0.2-0.1,0.4-0.2,0.6-0.4c0.2-0.2,0.5-0.5,0.7-1c0.3-0.4,0.5-1,0.8-1.7c0.2-0.4,0.3-0.9,0.5-1.4c0.1-0.5,0.2-0.9,0.3-1.4
c0.1-0.4,0.1-0.9,0.1-1.2c0-0.4,0-0.7,0-0.8c0-1-0.1-1.9-0.2-2.5c-0.1-0.7-0.3-1.2-0.6-1.6c-0.2-0.4-0.5-0.7-0.8-0.9
c-0.3-0.2-0.6-0.3-1-0.3c-0.2,0-0.4,0-0.5,0c-0.2,0-0.3,0.1-0.5,0.2c-0.2,0.1-0.4,0.3-0.4,0.4C77,2.8,77,2.9,77,3s0,0.2,0.1,0.2
c0,0,0.1,0.1,0.1,0.1c0,0.1,0,0.1-0.1,0.1c-0.1,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.1-0.3-0.1-0.5c0-0.3,0.1-0.5,0.2-0.8
c0.1-0.2,0.3-0.4,0.5-0.6c0.2-0.2,0.5-0.3,0.8-0.4c0.3-0.1,0.6-0.1,1-0.1c0.5,0,0.9,0.1,1.3,0.3c0.4,0.2,0.8,0.5,1.1,0.9
c0.3,0.4,0.5,1,0.7,1.6C82.5,4.4,82.5,5.3,82.5,6.3L82.5,6.3z M78.4,8.8c-0.1,0-0.2,0.1-0.4,0.4c-0.1,0.3-0.3,0.6-0.4,1
c-0.1,0.4-0.3,0.7-0.4,1.1C77.1,11.6,77,11.9,77,12c0.1-0.1,0.2-0.3,0.4-0.5c0.1-0.2,0.3-0.4,0.4-0.6c0.1-0.2,0.2-0.5,0.3-0.7
c0.1-0.2,0.2-0.4,0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.5C78.5,8.9,78.5,8.8,78.4,8.8L78.4,8.8z"/>
<path class="st3" d="M92.1,14.8c-0.5,0.4-1,0.7-1.5,1.1c-0.5,0.3-1,0.6-1.4,0.9c-0.4,0.2-0.8,0.4-1.1,0.4c-0.2,0-0.4-0.1-0.5-0.3
c-0.1-0.2-0.2-0.4-0.2-0.7c0-0.1,0-0.3,0-0.5c0-0.2,0-0.4,0.1-0.6c0-0.2,0.1-0.4,0.1-0.6c0-0.2,0.1-0.3,0.1-0.4h-0.1
c-0.6,0.8-1.3,1.4-2,1.9c-0.7,0.5-1.3,0.7-1.9,0.7c-0.5,0-0.9-0.2-1-0.5c-0.2-0.3-0.3-0.8-0.3-1.4c0-0.4,0.1-0.8,0.2-1.3
c0.1-0.5,0.3-1,0.5-1.4c0.2-0.5,0.5-1,0.8-1.4c0.3-0.5,0.6-0.9,1-1.2c0.9-0.9,1.8-1.5,2.6-1.8C88.3,7.2,89,7,89.8,7
c0.1,0,0.3,0,0.5,0.1c0.2,0,0.4,0.1,0.6,0.2c0.2,0.1,0.4,0.2,0.5,0.4c0.1,0.2,0.2,0.4,0.2,0.6c0,0.2,0,0.3,0,0.4
c0,0.1-0.1,0.2-0.1,0.3c-0.1,0.1-0.1,0.2-0.2,0.3c-0.1,0.1-0.2,0.2-0.4,0.3c-0.1,0.3-0.2,0.6-0.4,0.9c-0.1,0.3-0.3,0.6-0.5,1.1
c-0.3,0.9-0.6,1.7-0.8,2.3c-0.2,0.6-0.3,1-0.3,1.2c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.2,0.1,0.3,0.1c0.3,0,0.5-0.1,0.8-0.2
c0.3-0.1,0.6-0.3,0.9-0.5c0.3-0.2,0.7-0.5,1-0.7c0.3-0.3,0.7-0.5,1-0.8l0.2,0.3C93,14.1,92.6,14.4,92.1,14.8L92.1,14.8z
M90.3,8.5c0-0.1-0.1-0.2-0.2-0.3C90,8.1,89.9,8,89.8,8c-0.1-0.1-0.3-0.1-0.4-0.1c-0.1,0-0.2,0-0.3,0c-0.4,0-0.7,0-1,0.1
c-0.3,0.1-0.6,0.2-0.9,0.4c-0.3,0.2-0.6,0.4-0.9,0.8c-0.3,0.3-0.6,0.7-0.9,1.2c-0.2,0.3-0.3,0.6-0.5,0.9
c-0.1,0.4-0.3,0.7-0.4,1.1c-0.1,0.4-0.2,0.7-0.3,1c-0.1,0.3-0.1,0.6-0.1,0.8c0,0.5,0.1,0.8,0.3,0.9c0.2,0.2,0.4,0.2,0.6,0.2
c0.5,0,1-0.2,1.6-0.7c0.6-0.5,1.1-1.2,1.6-2.3c0.2-0.5,0.4-0.9,0.5-1.3c0.1-0.4,0.2-0.7,0.4-1.1c0-0.1,0.1-0.3,0.2-0.4
c0.1-0.2,0.2-0.3,0.3-0.5c0.1-0.1,0.2-0.3,0.4-0.4C90.1,8.5,90.2,8.5,90.3,8.5L90.3,8.5z"/>
</g>
<g>
<path class="st4" d="M147.2,12.4c-1.6,0-2.9,1.3-2.9,2.9s1.3,2.9,2.9,2.9s2.9-1.3,2.9-2.9S148.8,12.4,147.2,12.4z M147.2,17.6
c-1.3,0-2.3-1-2.3-2.3s1-2.3,2.3-2.3s2.3,1,2.3,2.3S148.5,17.6,147.2,17.6z"/>
<g>
<path class="st5" d="M146.1,13.4c0.2,0,0.6-0.1,0.9-0.1c0.5,0,0.8,0.1,1.1,0.3c0.2,0.2,0.3,0.4,0.3,0.7c0,0.5-0.3,0.8-0.7,1v0
c0.3,0.1,0.5,0.4,0.5,0.8c0.1,0.5,0.2,0.9,0.3,1H148c-0.1-0.1-0.1-0.4-0.2-0.9c-0.1-0.5-0.3-0.7-0.7-0.7h-0.5v1.6h-0.5V13.4z
M146.6,15.1h0.5c0.5,0,0.8-0.3,0.8-0.7c0-0.5-0.3-0.7-0.9-0.7c-0.2,0-0.4,0-0.5,0V15.1z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200" width="400" height="200" fill="#FFFFFF">
<rect width="400" height="200" fill="white"/>
<g transform="translate(0,72)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.7399 0L67.8599 39.93L54.2799 59.93L27.1599 20L40.7399 0Z"
fill="#C35F1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.58 0L40.74 39.99L27.16 59.99L0 20L13.58 0Z"
fill="#EC7316"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M67.9001 0L81.4001 20L67.8601 39.93L54.3201 20L67.9001 0Z"
fill="#A04F23"/>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M54.3201 19.9995L56.9101 16.1895L67.8601 39.9295L54.3201 19.9995Z" fill="#85411E"/>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M27.1599 19.9995L29.7499 16.1895L40.7199 39.9595L27.1599 19.9995Z" fill="#85411E"/>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M130.49 11.1504H129.4L126.07 34.3404L120.95 11.2004H114.95H114.79H114.04L108.59 35.8404L105.02 11.1604H96.3401L102.34 52.5104H112.6L117.52 31.0404L122.43 52.5104H132.14L138.14 11.1604H130.49V11.1504ZM159.67 11.1504H151.89C149.409 11.1557 147.032 12.1435 145.277 13.8977C143.523 15.6519 142.535 18.0296 142.53 20.5104V43.1504C142.533 45.632 143.52 48.0112 145.274 49.766C147.029 51.5208 149.408 52.5077 151.89 52.5104H159.7C162.182 52.5077 164.561 51.5208 166.316 49.766C168.07 48.0112 169.057 45.632 169.06 43.1504V20.5104C169.055 18.0244 168.063 15.6422 166.302 13.8871C164.541 12.1321 162.156 11.1477 159.67 11.1504ZM160.44 41.8104C160.437 42.3692 160.214 42.9044 159.819 43.2995C159.424 43.6946 158.889 43.9178 158.33 43.9204H153.2C152.641 43.9178 152.106 43.6946 151.711 43.2995C151.316 42.9044 151.093 42.3692 151.09 41.8104V21.8104C151.093 21.2516 151.316 20.7164 151.711 20.3213C152.106 19.9262 152.641 19.703 153.2 19.7004H158.33C158.889 19.703 159.424 19.9262 159.819 20.3213C160.214 20.7164 160.437 21.2516 160.44 21.8104V41.8104ZM384.42 11.1504H367.34V52.5104H384.42C386.901 52.5051 389.279 51.5173 391.033 49.7631C392.787 48.0089 393.775 45.6312 393.78 43.1504V20.5104C393.775 18.0296 392.787 15.6519 391.033 13.8977C389.279 12.1435 386.901 11.1557 384.42 11.1504ZM385.19 41.8104C385.187 42.3709 384.963 42.9076 384.566 43.303C384.168 43.6984 383.631 43.9204 383.07 43.9204H375.89V19.7404H383.03C383.591 19.7404 384.128 19.9624 384.526 20.3578C384.923 20.7532 385.147 21.2899 385.15 21.8504L385.19 41.8104ZM184.09 11.1504H191.89C194.371 11.1557 196.748 12.1435 198.503 13.8977C200.257 15.6519 201.245 18.0296 201.25 20.5104V43.1504C201.247 45.632 200.26 48.0112 198.506 49.766C196.751 51.5208 194.372 52.5077 191.89 52.5104H184.09C181.609 52.5051 179.231 51.5173 177.477 49.7631C175.723 48.0089 174.735 45.6312 174.73 43.1504V20.5104C174.735 18.0296 175.723 15.6519 177.477 13.8977C179.231 12.1435 181.609 11.1557 184.09 11.1504ZM192.039 43.2995C192.434 42.9043 192.657 42.3692 192.66 41.8104V21.8104C192.657 21.2516 192.434 20.7164 192.039 20.3213C191.644 19.9262 191.109 19.703 190.55 19.7004H185.43C184.869 19.7004 184.332 19.9224 183.934 20.3178C183.537 20.7132 183.313 21.2499 183.31 21.8104V41.8104C183.313 42.3709 183.537 42.9076 183.934 43.303C184.332 43.6984 184.869 43.9204 185.43 43.9204H190.55C191.109 43.9178 191.644 43.6946 192.039 43.2995ZM297.78 20.5104V29.3404C297.771 31.1409 297.242 32.9005 296.257 34.4081C295.273 35.9158 293.875 37.1075 292.23 37.8404L298.53 52.5104H290.28H289.12L283.19 38.6604H279.89V52.5104H271.34V11.1504H288.41C290.892 11.1557 293.271 12.1432 295.026 13.8971C296.782 15.651 297.772 18.0287 297.78 20.5104ZM288.563 29.4901C288.959 29.0953 289.185 28.5601 289.19 28.0004L289.15 21.8504C289.147 21.2899 288.923 20.7532 288.526 20.3578C288.128 19.9624 287.591 19.7404 287.03 19.7404H279.89V30.1104H287.07C287.63 30.1078 288.166 29.885 288.563 29.4901ZM360.49 11.1504H353.05V31.2704L343.69 11.1604H335.47V52.5104H344.06V32.3404L353.45 52.5204H361.63V11.1604H360.49V11.1504ZM310.07 11.1504H322.07L323.14 11.1604L331.69 52.5104H322.89L321.56 46.2504H311.56L310.27 52.5004H301.51L310.07 11.1504ZM316.61 21.9704L313.36 37.6704H319.89L316.61 21.9704ZM224.04 11.1504H206.96V52.5104H224.04C226.522 52.5077 228.901 51.5208 230.656 49.766C232.41 48.0112 233.397 45.632 233.4 43.1504V20.5104C233.395 18.0296 232.407 15.6519 230.653 13.8977C228.898 12.1435 226.521 11.1557 224.04 11.1504ZM224.81 41.8104C224.807 42.3692 224.584 42.9043 224.189 43.2995C223.794 43.6946 223.259 43.9178 222.7 43.9204H215.56V19.7404H222.7C223.259 19.743 223.794 19.9662 224.189 20.3613C224.584 20.7564 224.807 21.2916 224.81 21.8504V41.8104ZM248.47 11.1504H256.27C258.587 11.1659 260.816 12.0374 262.529 13.5972C264.242 15.1571 265.318 17.2952 265.55 19.6004C265.583 19.6761 265.6 19.7578 265.6 19.8404V24.5404H257.01V21.8104C257.007 21.2499 256.783 20.7132 256.386 20.3178C255.988 19.9224 255.451 19.7004 254.89 19.7004H249.77C249.211 19.703 248.676 19.9262 248.281 20.3213C247.886 20.7164 247.663 21.2516 247.66 21.8104V41.8104C247.663 42.3692 247.886 42.9043 248.281 43.2995C248.676 43.6946 249.211 43.9178 249.77 43.9204H254.89C255.171 43.9257 255.45 43.8751 255.711 43.7716C255.973 43.668 256.211 43.5136 256.412 43.3173C256.613 43.1209 256.772 42.8866 256.882 42.6279C256.992 42.3692 257.049 42.0913 257.05 41.8104V37.4904H251.16V29.6404H265.64V43.1504C265.635 45.6329 264.646 48.0121 262.889 49.7666C261.133 51.5211 258.753 52.5077 256.27 52.5104H248.47C245.988 52.5077 243.607 51.5211 241.851 49.7666C240.095 48.0121 239.105 45.6329 239.1 43.1504V20.5104C239.108 18.0287 240.098 15.651 241.854 13.8971C243.61 12.1432 245.988 11.1557 248.47 11.1504Z"
fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

View File

@@ -4,7 +4,7 @@ import {AuthProvider} from "../context/AuthContext";
import {createTTheme} from "../styles/theme/create-theme"; import {createTTheme} from "../styles/theme/create-theme";
import {Experimental_CssVarsProvider as CssVarsProvider} from '@mui/material/styles'; import {Experimental_CssVarsProvider as CssVarsProvider} from '@mui/material/styles';
import {BrowserRouter as Router} from "react-router-dom"; import {BrowserRouter as Router} from "react-router-dom";
import {NavigationRoutes} from "./NavigationRoutes"; import {NavigationRoutes} from "../components/navigation/NavigationRoutes";
import {SnackbarProvider} from 'notistack'; import {SnackbarProvider} from 'notistack';
import {UserProvider} from "../context/UserContext"; import {UserProvider} from "../context/UserContext";
import {SelectProvider} from "../context/SelectContext"; import {SelectProvider} from "../context/SelectContext";
@@ -15,7 +15,7 @@ function App() {
return ( return (
// Провайдер времени // Провайдер времени
<LocalizationProvider> <LocalizationProvider>
{/*Провайдер уведомлений*/} {/* Провайдер уведомлений*/}
<SnackbarProvider maxSnack={6} anchorOrigin={{vertical: 'bottom', horizontal: 'right'}} <SnackbarProvider maxSnack={6} anchorOrigin={{vertical: 'bottom', horizontal: 'right'}}
style={{borderRadius: '10px'}}> style={{borderRadius: '10px'}}>
{/*Провайдер авторизации*/} {/*Провайдер авторизации*/}

View File

@@ -1,10 +0,0 @@
import {paths} from "../path";
import {Loading} from "../components/core/Loading";
export function HomeRedirect({auth}) {
const redirectPath = auth ? paths.dashboard.overview : paths.auth.signIn;
window.location.replace(redirectPath);
return (
<Loading loading={true}/>
)
}

View File

@@ -1,4 +1,3 @@
import {SideNav} from "../../components/navigation/SideNav";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import {MainNav} from "../../components/navigation/MainNav"; import {MainNav} from "../../components/navigation/MainNav";
import Container from "@mui/material/Container"; import Container from "@mui/material/Container";
@@ -14,12 +13,10 @@ export function UserLayout({children}) {
minHeight: '100%', minHeight: '100%',
}} }}
> >
<SideNav/>
<Box sx={{ <Box sx={{
display: 'flex', display: 'flex',
flex: '1 1 auto', flex: '1 1 auto',
flexDirection: 'column', flexDirection: 'column',
pl: {xl: 'var(--SideNav-width)'}
}}> }}>
<MainNav/> <MainNav/>
<Container maxWidth="xl" sx={{py: '16px'}}> <Container maxWidth="xl" sx={{py: '16px'}}>

View File

@@ -1,79 +0,0 @@
import Paper from "@mui/material/Paper";
import React, {useEffect, useState} from "react";
import {useAlert} from "../../hooks/useAlert";
import {Card} from "@mui/material";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import Box from "@mui/material/Box";
import DeleteIcon from '@mui/icons-material/Delete';
import ElectricalServicesIcon from '@mui/icons-material/ElectricalServices';
import Toolbar from "@mui/material/Toolbar";
import AddCircleIcon from '@mui/icons-material/AddCircle';
import {BarCreateModal} from "../../components/BarCreateModal";
import PowerIcon from '@mui/icons-material/Power';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import {barClient} from "../../lib/clients/BarClient";
export function BarChangePage() {
const [bars, setBars] = useState([])
const [open, setOpen] = useState(false)
const [oldId, setOldId] = useState(null);
const {createError, createSuccess, createWarning} = useAlert();
const createHandler = (id, name) => {
if (id) {
barClient.copyBar(id, name, setBars, bars, createError, createSuccess, setOpen)
} else {
barClient.createBar(name, bars, createSuccess, createError, setBars, setOpen)
}
}
// eslint-disable-next-line
useEffect(() => barClient.getBarList(setBars, createError), []);
return (<>
<BarCreateModal open={open} setOpen={setOpen} create={createHandler} id={oldId}/>
<Paper sx={{p: 1}}>
<Toolbar>
<Typography variant='h6'>Списки ингредиентов (бары)</Typography>
<IconButton edge="end" onClick={() => {
setOldId(null);
setOpen(true);
}}>
<AddCircleIcon/>
</IconButton>
</Toolbar>
{bars.map((b) => {
return <Card key={b.id} sx={{m: 2, p: 2}}>
<Stack direction='row' justifyContent={'space-between'}>
<Typography>{b.name}</Typography>
<Box>
<IconButton onClick={() => {
setOldId(b.id)
setOpen(true);
}}>
<ContentCopyIcon/>
</IconButton>
{b.active && <IconButton disabled>
<PowerIcon/>
</IconButton>}
{!b.active && <>
<IconButton
onClick={() => barClient.deleteBar(b, bars, createError, createSuccess, setBars)}>
<DeleteIcon/>
</IconButton>
<IconButton
onClick={() => barClient.changeBar(b.id, bars, createWarning, createSuccess, createError, setBars)}>
<ElectricalServicesIcon/>
</IconButton>
</>}
</Box>
</Stack>
</Card>
})}
</Paper>
</>
)
}

View File

@@ -1,90 +0,0 @@
import Typography from "@mui/material/Typography";
import * as React from "react";
import {useEffect, useMemo} from "react";
import {useAlert} from "../../../hooks/useAlert";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import {CocktailItemCalc} from "./CocktailItemCalc";
import {IngredientCalcCard} from "./IngredientCalcCard";
import {cocktailClient} from "../../../lib/clients/CocktailClient";
export function CalcPage() {
const {createError} = useAlert();
const [cocktails, setCocktails] = React.useState([]);
const [load, setLoad] = React.useState(false);
const [cocktailMap, setCocktailMap] = React.useState({});
const changeHandler = (id, value) => {
setCocktailMap((prev) => ({
...prev,
[id]: value
}));
}
useEffect(() => {
cocktailClient.getCocktailsForCalcPage(load, setLoad, setCocktails, setCocktailMap, createError)
// eslint-disable-next-line
}, [load]);
const ingredients = useMemo(() => {
let map = {}
if (!cocktails) {
return [];
}
cocktails.forEach((c) => {
const receipts = c.receipt;
const countMeter = cocktailMap[c.id];
if (!receipts) {
return
}
receipts.forEach((r) => {
const ingredient = r.ingredient;
const id = ingredient.id;
const ingredientCount = r.count;
const resultCount = ingredientCount * countMeter;
if (map[id]) {
map[id] = {
...map[id],
count: map[id].count + resultCount
}
} else {
map[id] = {
ingredient: ingredient,
count: resultCount
}
}
})
})
return Object.values(map);
},
[cocktails, cocktailMap])
const deleteHandler = (id) => {
const state = cocktails.filter((c) => c.id !== id);
setCocktails(state);
}
console.log(cocktailMap)
return (
<Box padding={2}>
<Typography variant="h4" align="center">Коктейли</Typography>
<Stack mt={2}>
{cocktails.map((item, i) => (
<CocktailItemCalc key={i} cocktail={item} deleteHandler={deleteHandler}
changeHandler={changeHandler}/>
))}
</Stack>
<Typography variant="h4" mt={2} align="center">Ингредиенты</Typography>
<Stack mt={2}>
{ingredients.map((item, i) => (
<IngredientCalcCard key={i} count={item.count} ingredient={item.ingredient}/>
))}
</Stack>
</Box>
)
}

View File

@@ -1,40 +0,0 @@
import {Card} from "@mui/material";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import IconButton from "@mui/material/IconButton";
import DeleteIcon from "@mui/icons-material/Delete";
import React from "react";
import Typography from "@mui/material/Typography";
import {Counter} from "./Counter";
export function CocktailItemCalc({cocktail, deleteHandler, changeHandler}) {
return (
<Card sx={{mb: 1, display: 'relative', p: 2}}>
<Stack justifyContent={'start'} spacing={2}>
<Stack direction='row' justifyContent='start' alignItems='center'>
<Box sx={{width: '100px', height: '100px'}}>
<img src={cocktail.image} loading='lazy' height={'100px'} width={'100px'} alt={cocktail.id}/>
</Box>
<Box sx={{width: 'calc(90% - 100px)', pr: 2, ml: 2}}>
<Stack>
<Typography>{cocktail.name}</Typography>
<Typography>{cocktail.volume}</Typography>
<Typography>{cocktail.category}</Typography>
<Typography>{cocktail.alcoholic}</Typography>
<Typography color={'textSecondary'}>{cocktail.components}</Typography>
</Stack>
</Box>
<Stack direction='row'>
<Stack sx={{width: '5%'}} spacing={1} justifyContent='flex-start'>
<IconButton size='small' onClick={() => deleteHandler(cocktail.id)}>
<DeleteIcon/>
</IconButton>
</Stack>
</Stack>
</Stack>
<Counter id={cocktail.id} changeHandler={changeHandler}/>
</Stack>
</Card>
)
}

View File

@@ -1,65 +0,0 @@
import React, {useState} from 'react';
import {Box, TextField, Button} from '@mui/material';
import {styled} from '@mui/material/styles';
// Стилизуем контейнер счетчика
styled(Box)`
display: flex;
align-items: center;
justify-content: center;
width: 150px;
height: 50px;
border-radius: 8px;
//box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
//background-color: #ffffff;
`;
export function Counter({id, changeHandler}) {
const [value, setValue] = useState(1);
const handleChange = (newValue) => {
setValue(newValue);
changeHandler(id, newValue);
}
return (
<Box>
<Button onClick={() => {
if (value > 0) {
setValue(value - 1);
}
}}
sx={{
width: '20px',
height: '55px',
borderRadius: '50%',
margin: '0 8px',
backgroundColor: 'transparent',
}}></Button>
<TextField
value={value}
onChange={(e) => {
const newValue = parseInt(e.target.value, 10);
if (!isNaN(newValue)) {
handleChange(newValue);
}
}}
inputProps={{inputMode: 'numeric'}}
sx={{
width: '40px',
height: '15px',
fontSize: '10px',
textAlign: 'center'
}}
/>
<Button onClick={() => handleChange(value + 1)}
sx={{
width: '20px',
height: '55px',
borderRadius: '50%',
margin: '0 8px',
backgroundColor: 'transparent',
}}>+</Button>
</Box>
);
}

View File

@@ -1,21 +0,0 @@
import {Card} from "@mui/material";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import React from "react";
export function IngredientCalcCard({ingredient, count}) {
return (
<Card sx={{mb: 1, height: '130px', display: 'relative', pt: 1}}>
<Stack direction='row' justifyContent='start' alignItems='center'>
<Box sx={{width: '100px', height: '100px'}}>
<img src={ingredient.image} loading='lazy' height={'100px'} width={'100px'} alt={ingredient.id}/>
</Box>
<Box sx={{width: 'calc(90% - 100px)', pr: 2}}>{ingredient.name}</Box>
<Stack direction='row'>
<Box mr={1} pt={'3px'}>{count}</Box>
</Stack>
</Stack>
</Card>
)
}

View File

@@ -0,0 +1,23 @@
import React from 'react';
import {Container,} from '@mui/material';
import {CalendarContent} from "../../../components/calendar/CalendarContent";
import {Footer} from "../../../components/core/Footer";
import CalendarHeader from "../../../components/calendar/CalendarHeader";
const CalendarPage = () => {
// const [selectedClass, setSelectedClass] = useState('Все');
return (
<Container maxWidth={false} disableGutters sx={{px: {xs: 1, sm: 3, md: 6}}}>
{/* Шапка */}
<CalendarHeader selectedClass={'Все'} setSelectedClass={null}/>
{/* Основной контент */}
<CalendarContent selectedClass={'Все'}/>
{/* Подвал */}
<Footer/>
</Container>
);
}
export default CalendarPage;

View File

@@ -0,0 +1,229 @@
// src/pages/ChampionshipPage.jsx
import React, { useState, useEffect } from 'react';
import {
Container,
Typography,
Paper,
Box,
Button,
Chip,
Divider,
Alert,
CircularProgress
} from '@mui/material';
import { Launch as LaunchIcon, Download as DownloadIcon } from '@mui/icons-material';
import { useParams, Link } from 'react-router-dom';
// Импортируем константы (из предыдущего файла)
import { MOCK_STAGES, STAGE_STATUSES } from '../../../data/constants';
const ChampionshipPage = () => {
const { id } = useParams();
const [championship, setChampionship] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
useEffect(() => {
// Имитируем запрос на сервер
const fetchChampionship = async () => {
setLoading(true);
setError(false);
try {
// В реальном проекте тут будет fetch(`/api/championships/${id}`)
// Для примера фильтруем MOCK_STAGES по id этапа (упрощённо)
const stagesForChampionship = MOCK_STAGES.filter(stage => stage.stage.id === Number(id));
if (stagesForChampionship.length === 0) {
setError(true);
} else {
// Формируем данные чемпионата на основе первого подходящего этапа
const stage = stagesForChampionship[0];
setChampionship({
id: stage.stage.id,
title: stage.title,
description: stage.description || 'Информация о чемпионате отсутствует.',
regulationsUrl: '/regular/Pokrovsk_Cup_2026.pdf', // Условный URL регламента
stages: MOCK_STAGES.filter(s => s.title === stage.title) // Все этапы этого чемпионата
});
}
} catch (err) {
setError(true);
} finally {
setLoading(false);
}
};
fetchChampionship();
}, [id]);
if (loading) {
return (
<Container maxWidth="lg" sx={{ py: 4, textAlign: 'center' }}>
<CircularProgress />
<Typography sx={{ mt: 2 }}>Загрузка данных чемпионата...</Typography>
</Container>
);
}
if (error || !championship) {
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Alert severity="error" sx={{ mb: 3 }}>
Чемпионат не найден или произошла ошибка при загрузке данных.
</Alert>
<Button variant="contained" onClick={() => window.history.back()}>
Вернуться назад
</Button>
</Container>
);
}
// Сортируем этапы: сначала предстоящие (регистрация открыта / идёт), потом прошедшие
const sortedStages = [...championship.stages].sort((a, b) => {
const isAPast = a.status === STAGE_STATUSES.COMPLETED;
const isBPast = b.status === STAGE_STATUSES.COMPLETED;
if (isAPast && !isBPast) return 1;
if (!isAPast && isBPast) return -1;
return 0; // Сохраняем порядок для этапов одного типа
});
return (
<Container maxWidth="lg" sx={{ pt: 4 }}>
{/* Заголовок и основная информация */}
<Typography variant="h4" gutterBottom>
{championship.title}
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
{championship.description}
</Typography>
{/* Кнопка загрузки регламента */}
<Button
variant="outlined"
startIcon={<DownloadIcon />}
href={championship.regulationsUrl}
target="_blank"
rel="noopener noreferrer"
sx={{ mb: 4 }}
>
Скачать регламент
</Button>
<Divider sx={{ mb: 4 }} />
{/* Список этапов */}
<Typography variant="h5" gutterBottom>Этапы чемпионата</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
{sortedStages.map((stage) => (
<Paper
component={Link}
to={"/stages/" + stage.stage.id}
key={stage.stage.id}
variant="outlined"
sx={{
p: 3,
'&:hover': { boxShadow: 3 },
transition: 'box-shadow 0.2s',
textDecoration: 'none'
}}
onClick={() => window.location.replace()}
>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
<Typography variant="subtitle1" fontWeight={600}>
{stage.stage.name}
</Typography>
<Chip
label={stage.status}
color={
stage.status === STAGE_STATUSES.GOING
? 'warning'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info'
: 'default'
}
sx={{
backgroundColor:
stage.status === STAGE_STATUSES.GOING
? 'warning.dark'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success.dark'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info.dark'
: 'grey.300',
color: 'white',
fontWeight: 500,
fontSize: '0.8rem'
}}
/>
</Box>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
{new Date(stage.date).toLocaleDateString('ru-RU', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</Typography>
<Typography variant="body2" sx={{ mb: 1 }}>
Место: {stage.location}
</Typography>
{stage.description && (
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
{stage.description}
</Typography>
)}
{/* Бейджи вместо кнопок */}
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
{stage.status === STAGE_STATUSES.REGISTRATION_OPEN && (
<Chip
label="Регистрация открыта"
color="success"
variant="outlined"
icon={<LaunchIcon fontSize="small" />}
/>
)}
{stage.status === STAGE_STATUSES.COMPLETED && (
<Chip
label="Результаты"
color="primary"
variant="outlined"
icon={<LaunchIcon fontSize="small" />}
/>
)}
{(stage.status === STAGE_STATUSES.GOING ||
stage.status === STAGE_STATUSES.PRE_REGISTRATION) && (
<Chip
label={
stage.status === STAGE_STATUSES.GOING
? 'Идёт сейчас'
: 'Предрегистрация'
}
color={stage.status === STAGE_STATUSES.GOING ? 'warning' : 'info'}
variant="outlined"
/>
)}
</Box>
</Paper>
))}
</Box>
<Divider sx={{ my: 4 }} />
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Все права защищены.
</Typography>
</Container>
);
};
export default ChampionshipPage;

View File

@@ -0,0 +1,20 @@
import React from 'react';
import {Container,} from '@mui/material';
import ChampionshipHeader from "../../../components/championship/ChampionshipHeader";
import ChampionshipsList from "../../../components/championship/ChampionshipsList";
import {Footer} from "../../../components/core/Footer";
const ChampionshipsPage = () => {
return (
<Container maxWidth="xl" sx={{pt: 6}}>
{/* Заголовок и кнопка создания */}
<ChampionshipHeader/>
{/* Список чемпионатов */}
<ChampionshipsList/>
{/* Подвал */}
<Footer/>
</Container>
);
};
export default ChampionshipsPage;

View File

@@ -1,196 +0,0 @@
import Grid from "@mui/material/Grid";
import {useAlert} from "../../../hooks/useAlert";
import * as React from "react";
import {useCallback, useEffect, useState} from "react";
import {Cocktail} from "../../../components/cocktails/Cocktail";
import {Fab, Skeleton} from "@mui/material";
import Box from "@mui/material/Box";
import {NoResult} from "../../../components/cocktails/NoResult";
import {FilterBlock} from "../../../components/cocktails/FilterBlock";
import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
import {useUser} from "../../../hooks/useUser";
import {blue} from "@mui/material/colors";
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
import {useSelect} from "../../../hooks/useSelect";
import Paper from "@mui/material/Paper";
import CheckMarks from "../../../components/cocktails/CheckMarks";
import {cocktailClient} from "../../../lib/clients/CocktailClient";
const emptyFilter = {
search: "",
all: false,
hidden: true,
onlyFavourite: false,
glass: [],
category: [],
alcohol: [],
iCount: [],
ingredient: [],
inMenu: "",
sorting: "Название по возрастанию"
}
const CocktailsPageContent = () => {
const {user} = useUser();
const {createError, createSuccess} = useAlert();
const [rows, setRows] = useState([]);
const [filter, setFilter] = useState(emptyFilter)
// const [chips, setChips] = useState([])
const chips = [];
const [page, setPage] = useState(-1);
const [load, setLoad] = useState(false);
const [isEnd, setIsEnd] = useState(false);
const [isNew, setIsNew] = useState(true);
const {selectCocktail, getCocktail, getOpenCocktail} = useSelect();
const loading = useCallback(() => {
const size = Math.floor((window.innerWidth) / 350) * 5;
if (load || (!isNew && isEnd)) {
return false;
}
cocktailClient.getMenu(setRows, setIsNew, setPage, setLoad, setIsEnd, isNew, rows, page, size, filter, createError);
// eslint-disable-next-line
}, [load, isEnd, page]);
useEffect(() => {
const handleScroll = () => {
const {scrollTop, scrollHeight, clientHeight} = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 100) {
loading();
}
}
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
// eslint-disable-next-line
}, [loading]);
// eslint-disable-next-line
useEffect(() => loading(), [filter])
const renderSkeleton = () => {
return Array.from({length: 3}, () => null)
.map((v, index) => <Skeleton sx={{m: 2}}
key={index}
variant="rounded"
width={350}
height={690}/>);
}
const handleChangeRating = (row, value) => {
const newState = rows.map((r) => {
if (row.id === r.id) {
let newRating = r.rating;
newRating.rating = value
return {
...r,
rating: newRating
}
}
return r;
})
cocktailClient.changeRating(row.id, newState, value, setRows, createSuccess, createError)
}
const handleFilterChange = (filterName, value) => {
const newState = {
...filter,
[filterName]: value
}
setFilter(newState)
setIsNew(true);
setIsEnd(false);
setPage(-1);
}
const handleFavourite = (row) => {
const value = !row.rating.favourite;
const newState = rows.map((r) => {
if (r.id === row.id) {
let newRating = r.rating;
newRating.favourite = value;
return {
...r,
rating: newRating
}
}
return r;
});
cocktailClient.changeFavourite(value, row.id, newState, setRows, createSuccess, createError)
}
const handleFilterClear = () => {
setFilter(emptyFilter);
setIsNew(true);
setIsEnd(false);
setPage(-1);
}
const handleSelectCocktail = (row) => selectCocktail(row.id)
const deleteHandle = (row) => cocktailClient.deleteCocktail(row.id, rows, setRows, createSuccess, createError)
const hideHandler = (id) => {
cocktailClient.hiddenCocktail(id)
.then(() => {
createSuccess("Коктейль скрыт успешно");
setRows(rows.filter((r) => r.id !== id))
}).catch(() => createError("Ошибка при попытке скрыть коктейль"))
}
return (
<Box>
{/*<Loading loading={load}/>*/}
{/*Модальное окно информации о коктейле*/}
<CocktailInfoModal row={getCocktail()} open={getOpenCocktail()}/>
{/*Блок фильтров*/}
<FilterBlock
filter={filter}
handleFilterChange={handleFilterChange}
handleClearFilter={handleFilterClear}
barmen={user.role !== 'USER'}
/>
{
(filter.all && filter.iCount === 1) && (
<Paper sx={{mt: 1}}>
<CheckMarks rows={chips} name={"Выбор ингредиента"} filterName={"ingredient"}
filterValue={filter.ingredient}
handleChange={handleFilterChange}
identity
/>
</Paper>
)
}
<Box>
{/*Основное содержимое*/}
<Grid container rowSpacing={2} columnSpacing={{xs: 1, sm: 1, md: 2}} sx={{m: 1}}>
{rows.length > 0 && rows.map((row) => {
return (
<Cocktail key={row.id} row={row} handleFavourite={handleFavourite}
handleChangeRating={handleChangeRating}
handleSelect={handleSelectCocktail}
deleteHandler={deleteHandle}
hideHandler={hideHandler}
/>
)
})}
{load && renderSkeleton()}
{rows.length === 0 && (<NoResult/>)}
</Grid>
</Box>
<Fab sx={{
alpha: '30%',
position: 'sticky',
left: 'calc(100% - 16px)',
bottom: '16px',
color: 'common.white',
bgcolor: blue[600],
'&:hover': {
bgcolor: blue[600],
},
}}
onClick={() => window.window.scrollTo(0, 0)}
aria-label='Expand'
color='inherit'>
<UpIcon/>
</Fab>
</Box>
);
}
export default CocktailsPageContent;

View File

@@ -1,194 +0,0 @@
import Box from "@mui/material/Box";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import * as React from "react";
import {useEffect, useState} from "react";
import Paper from "@mui/material/Paper";
import {Autocomplete} from "@mui/material";
import TextField from "@mui/material/TextField";
import {useAlert} from "../../../hooks/useAlert";
import Stack from "@mui/material/Stack";
import Button from "@mui/material/Button";
import {EditCocktailReceipt} from "../../../components/cocktails/EditCocktailReceipt";
import {SelectEdit} from "../../../components/cocktails/SelectEdit";
import {useSearchParams} from "react-router-dom";
import {Loading} from "../../../components/core/Loading";
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import {styled} from "@mui/material/styles";
import {cocktailClient} from "../../../lib/clients/CocktailClient";
import {categoryClient} from "../../../lib/clients/CategoryClient";
import {glassClient} from "../../../lib/clients/GlassClient";
const emptyCocktail = {
id: null,
name: "",
alcoholic: "",
category: "",
components: "",
glass: "",
image: "",
instructions: "",
isAllowed: false,
rating: {
rating: 0,
favourite: false
},
receipt: [],
tags: "",
video: ""
};
const alcohol = [
{
id: 1,
name: "Алкогольный"
},
{
id: 2,
name: "Безалкогольный",
},
{
id: 3,
name: "Опционально"
}
]
const VisuallyHiddenInput = styled('input')({
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: 1,
overflow: 'hidden',
position: 'absolute',
bottom: 0,
left: 0,
whiteSpace: 'nowrap',
width: 1,
});
export function EditCocktailPage() {
const [searchParams] = useSearchParams();
const [loading, setLoading] = useState(true);
const {createError, createSuccess, getError} = useAlert();
const [cocktails, setCocktails] = useState([]);
const [selected, setSelected] = useState(null);
const [cocktail, setCocktail] = useState(emptyCocktail);
const [glass, setGlass] = useState([]);
const [category, setCategory] = useState([]);
useEffect(() => {
cocktailClient.getSimpleList(setCocktails, setSelected, setLoading, createError, searchParams.get("id"))
categoryClient.getCategoryList(setCategory, createError);
glassClient.getGlassList(setGlass, createError)
// eslint-disable-next-line
}, []);
// eslint-disable-next-line
useEffect(() => cocktailClient.getOneCocktail(selected, setCocktail, getError, emptyCocktail), [selected])
const saveHandler = () => cocktailClient.saveChangeCocktail(cocktail, createError, createSuccess)
const deleteHandle = () => cocktailClient.deleteCocktailFromEdit(setCocktails, setCocktail, createError, cocktails, cocktail, emptyCocktail)
const changeCocktailValue = (name, value) => {
if (name === "tags") {
value = value.join(",");
}
setCocktail((prev) => ({
...prev,
[name]: value
}))
}
return (
<Box>
{/*Загрузка*/}
<Loading loading={loading}/>
{/*Заголовок*/}
<Toolbar>
<Typography variant="h6" component="div" sx={{flexGrow: 1}}>Коктейли</Typography>
</Toolbar>
{/*Поиск*/}
<Paper elevation={6} sx={{my: 2, display: 'grid', p: 2}}>
<Autocomplete
disablePortal
options={cocktails}
onChange={(e, v) => {
if (!v) {
setCocktail(emptyCocktail);
setSelected(null)
} else {
setSelected(v.id)
}
}}
isOptionEqualToValue={(selected, value) => selected.id === value.id}
getOptionKey={(selected) => selected.id}
getOptionLabel={(selected) => selected.name + (selected.hasError ? " (есть ошибка)" : "")}
renderInput={(params) => <TextField {...params} label="Поиск"/>}
/>
</Paper>
{/*Рабочая область*/}
<Paper elevation={6} sx={{my: 2, display: 'grid', p: 1, pb: 2}}>
<Stack>
<Box hidden={cocktail.id === null} ml={1} mb={1}>
<Button color='error' onClick={() => deleteHandle()}>Удалить коктейль</Button>
</Box>
{/*Фото*/}
<Box ml={1}>
<img src={cocktail.image} alt={""} width={300} height={300} loading={'eager'}/>
</Box>
{/*Редактирование ссылки на фото*/}
<Stack direction='row' pr={2} m={1} display='relative'>
<TextField sx={{width: '75%'}}
label={"Ссылка на фото"} variant='outlined' multiline
value={!cocktail.image ? "" : cocktail.image}
onChange={(e) => changeCocktailValue("image", e.target.value)}
/>
<Button
component="label"
role={undefined}
variant="contained"
tabIndex={-1}
startIcon={<CloudUploadIcon/>}
sx={{width: '10%', fontSize: 40, ml: 1, pr: 1}}
>
<VisuallyHiddenInput
type="file"
accept=".jpg,.jpeg,.png"
onChange={(event) => cocktailClient.savePhoto(event, changeCocktailValue, getError)}
/>
</Button>
</Stack>
{/*Название*/}
<Box m={1}>
<TextField sx={{mr: 1, mb: 2, minWidth: 300}}
variant="outlined" label={"Название"}
value={cocktail.name}
onChange={(e) => changeCocktailValue("name", e.target.value)}/>
</Box>
{/*Категория, посуда, алкогольность, теги*/}
<Box mb={2}>
<SelectEdit value={cocktail.category} label={"Категория"} width={300} margin={1}
array={category}
attributeName={"category"} handler={changeCocktailValue}/>
<SelectEdit value={cocktail.glass} label={"Посуда"} width={300} margin={1} array={glass}
attributeName={"glass"} handler={changeCocktailValue}/>
<SelectEdit value={cocktail.alcoholic} label={"Алкогольность"} width={300} margin={1}
array={alcohol}
attributeName={"alcoholic"} handler={changeCocktailValue}/>
</Box>
{/*Рецепт*/}
<EditCocktailReceipt receipt={cocktail.receipt} handler={changeCocktailValue}/>
<Box pr={2} ml={1}>
<TextField sx={{width: '100%'}}
label={"Инструкция"} variant='outlined' multiline
value={!cocktail.instructions ? "" : cocktail.instructions}
onChange={(e) => changeCocktailValue("instructions", e.target.value)}
/>
</Box>
</Stack>
</Paper>
<Box display={'flex'} justifyContent={'flex-end'}>
<Button variant='contained' onClick={() => saveHandler()}>Сохранить</Button>
</Box>
</Box>
)
}

View File

@@ -1,7 +0,0 @@
import CocktailsPageContent from "./CocktailsPageContent";
export function MenuPage() {
return (
<CocktailsPageContent/>
)
}

View File

@@ -0,0 +1,43 @@
import * as React from "react";
import {useUser} from "../../../hooks/useUser";
import Container from "@mui/material/Container";
import AnnounceBlock from "../../../components/home/AnnounceBlock";
import WelcomeBlock from "../../../components/home/WelcomeBlock";
import SponsorsBlock from "../../../components/home/SponsorsBlock";
import RentBlock from "../../../components/home/RentBlock";
import {Footer} from "../../../components/core/Footer";
import NextStageTimer from "../../../components/home/NextStageTimer";
import LastResult from "../../../components/home/LastResult";
// Основной компонент приветственного блока
const HomePageContent = () => {
const {user} = useUser();
return (
<Container maxWidth="xl" sx={{py: 3}}>
{/* 1. Приветствие */}
<WelcomeBlock/>
{/* 2. Карточки анонсов */}
<AnnounceBlock/>
{/*//todo: вопрос о необходимости*/}
{/* 3. Быстрые действия */}
{/*<QuickActions/>*/}
{/* 4. Спонсоры */}
<SponsorsBlock/>
{/* 5. Прокат */}
<RentBlock/>
{/* 6. Таймер до ближайшего этапа (Honda Winter Cup) */}
<NextStageTimer/>
{/* 7. Результаты последнего этапа */}
<LastResult/>
{/* Разделитель и подвал */}
<Footer/>
</Container>
);
}
export default HomePageContent;

View File

@@ -0,0 +1,7 @@
import HomePageContent from "./HomePageContent";
export function MenuPage() {
return (
<HomePageContent/>
)
}

View File

@@ -1,142 +0,0 @@
import Box from "@mui/material/Box";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import * as React from "react";
import {useEffect, useState} from "react";
import Paper from "@mui/material/Paper";
import {Autocomplete, FormControl, FormControlLabel, InputLabel} from "@mui/material";
import {useAlert} from "../../../hooks/useAlert";
import {useSearchParams} from "react-router-dom";
import TextField from "@mui/material/TextField";
import Switch from "@mui/material/Switch";
import Stack from "@mui/material/Stack";
import Button from "@mui/material/Button";
import Select from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import {ingredientClient} from "../../../lib/clients/IngredientClient";
const emptyIngredient = {
id: null,
name: "",
enName: "",
have: false,
image: null,
type: "",
alcohol: false,
abv: null,
description: null
}
export function EditIngredientPage() {
const [searchParams] = useSearchParams();
const [ingredients, setIngredients] = useState([]);
const [types, setTypes] = useState([]);
const [ingredient, setIngredient] = useState(emptyIngredient)
const {createError, createSuccess} = useAlert();
useEffect(() => {
ingredientClient.allList(searchParams.get("id"), setIngredients, setIngredient, createError)
ingredientClient.getType(setTypes)
// eslint-disable-next-line
}, []);
const changeIngredientValue = (name, value) => {
setIngredient((prev) => ({
...prev,
[name]: value
}))
}
return (
<Box>
{/*Заголовок*/}
<Toolbar>
<Typography variant="h6" component="div" sx={{flexGrow: 1}}>Ингредиенты</Typography>
</Toolbar>
{/*Поиск*/}
<Paper elevation={6} sx={{my: 2, display: 'grid', p: 2}}>
<Autocomplete
disablePortal
options={ingredients}
defaultChecked={emptyIngredient}
onChange={(e, v) => {
return !v ? setIngredient(emptyIngredient) : setIngredient(v)
}}
isOptionEqualToValue={(selected, value) => selected.id === value.id}
getOptionKey={(selected) => selected.id}
getOptionLabel={(selected) => selected.name}
renderInput={(params) => <TextField {...params} label="Ингредиенты"/>}
/>
</Paper>
{/*Форма ингредиента*/}
<Paper elevation={6} sx={{my: 2, display: 'grid', p: 1, pb: 2}}>
<Stack>
<Box display={'flex'} justifyContent={'flex-end'} pr={2}>
<FormControlLabel control={
<Switch
checked={ingredient.have}
onChange={() => changeIngredientValue("have", !ingredient.have)}
/>}
label={"Наличие"} labelPlacement={'start'}/>
</Box>
<Box>
<img src={ingredient.image} alt={""} loading={'eager'}/>
</Box>
<Box m={1}>
<TextField sx={{mr: 1, mb: 2, minWidth: 330}}
variant="outlined" label={"Название"}
value={ingredient.name}
onChange={(e) => changeIngredientValue("name", e.target.value)}/>
</Box>
<Box height={70} mt={1} ml={1}>
<FormControlLabel sx={{pt: 1}}
control={
<Switch
checked={ingredient.alcohol}
onChange={() => changeIngredientValue("alcohol", !ingredient.alcohol)}
/>}
label="Алкогольный"/>
{ingredient.alcohol && (
<TextField sx={{width: 100}}
variant='outlined' label='Градус'
value={!ingredient.abv ? "" : ingredient.abv}
onChange={(e) => changeIngredientValue("abv", e.target.value)}/>
)}
</Box>
<Box mb={2} ml={1}>
<FormControl sx={{width: 330}}>
<InputLabel id="select-label">Категория</InputLabel>
<Select
id="select-label"
autoWidth
label={"Категория"}
value={!ingredient.type ? "" : ingredient.type}
onChange={(e) => changeIngredientValue("type", e.target.value)}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{types.map((c) => {
return (<MenuItem key={c.id} value={c.name}>{c.name}</MenuItem>)
})}
</Select>
</FormControl>
</Box>
<Box pr={2} ml={1}>
<TextField sx={{width: '100%'}}
label={"Описание"} variant='outlined' multiline
onChange={(e) => changeIngredientValue("description", e.target.value)}
value={!ingredient.description ? "" : ingredient.description}/>
</Box>
</Stack>
</Paper>
<Box display={'flex'} justifyContent={'flex-end'}>
<Button variant='contained'
onClick={() => ingredientClient.saveIngredient(ingredient, createSuccess, createError)}>Сохранить</Button>
</Box>
</Box>
)
}

View File

@@ -1,126 +0,0 @@
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Toolbar from "@mui/material/Toolbar";
import Paper from "@mui/material/Paper";
import {Fab, FormControl, InputAdornment, InputLabel, OutlinedInput, Tabs} from "@mui/material";
import IconButton from "@mui/material/IconButton";
import SearchIcon from "@mui/icons-material/Search";
import * as React from "react";
import {useEffect, useMemo, useState} from "react";
import {Loading} from "../../../components/core/Loading";
import {useAlert} from "../../../hooks/useAlert";
import {IngredientInfoModal} from "../../../components/Ingredients/IngredientInfoModal";
import Tab from "@mui/material/Tab";
import {a11yProps} from "../../../components/core/tabProps";
import {CustomTabPanel} from "../../../components/core/TabPanel";
import {IngredientList} from "../../../components/Ingredients/IngredientList";
import {blue} from "@mui/material/colors";
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
import {useSelect} from "../../../hooks/useSelect";
import {ingredientClient} from "../../../lib/clients/IngredientClient";
export function IngredientsPage() {
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => setValue(newValue);
const [loading, setLoading] = useState(true);
const [findString, setFindString] = useState("");
const [ingredients, setIngredients] = useState([]);
const {getIngredient, selectIngredient} = useSelect();
const {createError, createSuccess} = useAlert();
useEffect(() => {
ingredientClient.getAllIngredients(setIngredients, setLoading, createError)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const visibleIngredients = useMemo(() => {
if (findString.length === 0) {
return ingredients;
}
const reg = new RegExp("(.*?)" + findString + "(.*?)", "i");
return ingredients.filter((ingredient) => ingredient.name.match(reg) !== null);
}, [findString, ingredients]);
const ingredientsToAdd = visibleIngredients.filter((ingredient) => !ingredient.have);
const ingredientsInBar = visibleIngredients.filter((ingredient) => ingredient.have);
const changeHandler = (row, value) => {
const newState = ingredients.map((ingredient) => {
if (ingredient.id === row.id) {
return {
...ingredient,
have: value
}
} else {
return ingredient;
}
})
ingredientClient.changeIngredientIsHave(row.id, value, newState, setIngredients, createError)
}
const handleDelete = (id) => {
const newState = ingredients.filter((ingredient) => ingredient.id !== id);
setIngredients(newState)
ingredientClient.deleteIngredientIsHave(id, createSuccess, createError)
}
return (
<Box>
{/*Заголовок*/}
<Toolbar>
<Typography variant="h6" component="div" sx={{flexGrow: 1}}>Ингредиенты бара</Typography>
</Toolbar>
{/*Поиск*/}
<Paper elevation={6} sx={{my: 2}}>
<FormControl sx={{m: 1, width: 'calc(100% - 20px'}}>
<InputLabel htmlFor="outlined-adornment-amount">Поиск</InputLabel>
<OutlinedInput
onChange={(e) => setFindString(e.target.value)}
label="With normal TextField"
startAdornment={
<InputAdornment position="start">
<IconButton edge="end">
<SearchIcon/>
</IconButton>
</InputAdornment>
}
/>
</FormControl>
</Paper>
{/*Рабочее поле ингредиентов*/}
<Box>
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
<Tab label="В баре" {...a11yProps(0)} />
<Tab label="Список" {...a11yProps(1)} />
</Tabs>
</Box>
<Box>
<CustomTabPanel value={value} index={0}>
<IngredientList rows={ingredientsInBar} value={false} changeHandler={changeHandler}
infoHandler={selectIngredient}/>
</CustomTabPanel>
<CustomTabPanel value={value} index={1}>
<IngredientList rows={ingredientsToAdd} value={true} changeHandler={changeHandler}
infoHandler={selectIngredient}/>
</CustomTabPanel>
</Box>
<Fab sx={{
alpha: '30%',
position: 'sticky',
bottom: '16px',
color: 'common.white',
bgcolor: blue[600],
'&:hover': {
bgcolor: blue[600],
},
}}
onClick={() => window.window.scrollTo(0, 0)}
aria-label='Expand'
color='inherit'>
<UpIcon/>
</Fab>
{/*Загрузчик*/}
<Loading loading={loading}/>
{/*Модальное окно информации об ингредиенте*/}
<IngredientInfoModal ingredient={getIngredient()} handleDelete={handleDelete}/>
</Box>
)
}

View File

@@ -0,0 +1,88 @@
// src/routes/RacetrackDetail.jsx
import React from 'react';
import {useParams} from 'react-router-dom';
import {Box, Card, CardMedia, Container, Typography} from '@mui/material';
import {Link} from 'react-router-dom';
import {places} from "../../../data/constants";
import Carousel from "react-material-ui-carousel";
import Paper from "@mui/material/Paper";
import IconButton from "@mui/material/IconButton";
import KeyboardReturnIcon from '@mui/icons-material/KeyboardReturn';
import {paths} from "../../../path";
const PlacePage = () => {
const {id} = useParams();
// Здесь должен быть код для получения данных трассы по ID
let track = places.find((t) => t.id === Number(id));
if (!track) {
return <Typography>Трасса не найдена</Typography>;
}
// track = undefined;
return (
<Container maxWidth="lg" sx={{py: 4}}>
<Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
<Typography variant="h5">{track.name}</Typography>
<IconButton component={Link} to={paths.places.places}>
<KeyboardReturnIcon/>
</IconButton>
</Box>
<Box sx={{mt: 3}}>
<Carousel
swipe
sx={{
height: 400, // фиксированная высота карусели
'& .MuiCard-root': {
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
}}
>
{track.images.map((item, index) => (
<Card key={index} sx={{ width: '100%', height: '100%' }}>
<CardMedia
image={item}
alt={item}
component="img"
sx={{
width: '100%',
height: 'auto',
maxHeight: '100%',
objectFit: 'cover', // сохраняет пропорции, заполняет контейнер
objectPosition: 'center', // центрирует изображение
}}
/>
</Card>
))}
</Carousel>
</Box>
<Box sx={{mt: 3}}>
<Typography variant="subtitle1">Адрес:</Typography>
<Typography variant="body1">{track.address || 'Не указан'}</Typography>
</Box>
<Box sx={{mt: 2}}>
<Typography variant="subtitle1">Тип площадки:</Typography>
<Typography variant="body1">{track.type}</Typography>
</Box>
{track.capacity && (
<Box sx={{mt: 2}}>
<Typography variant="subtitle1">Вместимость:</Typography>
<Typography variant="body1">{track.capacity} человек</Typography>
</Box>
)}
<Box sx={{mt: 2}}>
<Typography variant="subtitle1">Контактные данные:</Typography>
<Typography variant="body1">{track.contact}</Typography>
</Box>
<Box sx={{mt: 2}}>
<Typography variant="subtitle1">Номер бронирования:</Typography>
<Typography variant="body1">{track.bookingNumber}</Typography>
</Box>
</Container>
);
};
export default PlacePage;

View File

@@ -0,0 +1,64 @@
// src/pages/RacetracksPage.jsx
import React from 'react';
import {
Container,
Typography,
Card,
CardActionArea,
CardMedia,
CardContent,
CardHeader,
Button,
Divider,
} from '@mui/material';
import { Link } from 'react-router-dom';
import {places} from "../../../data/constants";
const PlacesPage = () => {
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Typography variant="h4" gutterBottom>
Список гоночных трасс и картодромов
</Typography>
<Divider sx={{ my: 3 }} />
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '20px' }}>
{places.map((track) => (
<Card key={track.id} sx={{ width: '300px', height: '100%', p:1}}>
<CardActionArea component={Link} to={`/places/${track.id}`}>
<CardMedia
component="img"
height="200"
image={track.images[0]}
alt={track.name}
/>
<CardHeader title={track.name} />
<CardContent>
<Typography variant="body2" color="text.secondary">
{track.address ? track.address : 'Нет данных об адресе'}
</Typography>
<Typography variant="body2" color="text.secondary">
Тип: {track.type}
</Typography>
{track.capacity && (
<Typography variant="body2" color="text.secondary">
Вместимость: {track.capacity} человек
</Typography>
)}
</CardContent>
</CardActionArea>
<Button
variant="contained"
sx={{ mt: 1 }}
component={Link}
to={`/places/${track.id}`}
>
Подробнее
</Button>
</Card>
))}
</div>
</Container>
);
};
export default PlacesPage;

View File

@@ -0,0 +1,325 @@
import React, {useEffect, useState} from 'react';
import {
Alert,
Box,
Button,
Chip,
CircularProgress,
Container,
Paper,
Tab,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Tabs,
Typography
} from '@mui/material';
import {Download as DownloadIcon, Print as PrintIcon} from '@mui/icons-material';
import {useParams} from 'react-router-dom';
import {MOCK_STAGES, STAGE_STATUSES} from '../../../data/constants';
import StagesHeader from "../../../components/stages/StagesHeader";
const StagePage = () => {
const {id} = useParams();
const [stage, setStage] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [activeTab, setActiveTab] = useState('info'); // info | classes | events
const [activeClassTab, setActiveClassTab] = useState(0);
useEffect(() => {
const foundStage = MOCK_STAGES.find(s => s.id === Number(id));
if (foundStage) {
setStage(foundStage);
setLoading(false);
} else {
setError(true);
setLoading(false);
}
}, [id]);
if (loading) {
return (
<Container maxWidth="lg" sx={{py: 4, textAlign: 'center'}}>
<CircularProgress/>
<Typography sx={{mt: 2}}>Загрузка данных этапа...</Typography>
</Container>
);
}
if (error || !stage) {
return (
<Container maxWidth="lg" sx={{py: 4}}>
<Alert severity="error" sx={{mb: 3}}>
Этап не найден.
</Alert>
<Button variant="contained" onClick={() => window.history.back()}>
Вернуться назад
</Button>
</Container>
);
}
// Пример данных участников (в реальном проекте — из API)
const participants = {
'Юниоры': [
{id: 1, name: 'Иван Петров', number: 12},
{id: 2, name: 'Анна Сидорова', number: 7},
// ...
],
'Взрослые': [
{id: 3, name: 'Сергей Иванов', number: 25},
// резерв
{id: 4, name: 'Алексей Козлов', number: 99, isReserve: true},
]
};
const maxParticipantsPerClass = 10;
// Определяем сценарий
const isRegistrationClosed = stage.status === STAGE_STATUSES.PRE_REGISTRATION;
const isRegistrationOpen = stage.status === STAGE_STATUSES.REGISTRATION_OPEN;
const isInProgress = stage.status === STAGE_STATUSES.GOING;
const isCompleted = stage.status === STAGE_STATUSES.COMPLETED;
return (
<Container maxWidth="lg" sx={{py: 4}}>
{/* Шапка этапа */}
<StagesHeader stage={stage}/>
{/* Табы навигации */}
<Tabs
value={activeTab}
onChange={(e, newValue) => setActiveTab(newValue)}
sx={{mb: 3}}
>
<Tab label="Информация" value="info"/>
{(isRegistrationOpen || isInProgress || isCompleted) && (
<Tab label="Классы" value="classes"/>
)}
{(isInProgress || isCompleted) && <Tab label="События" value="events"/>}
</Tabs>
{/* Контент в зависимости от активного таба */}
{activeTab === 'info' && (
<Box>
<Typography variant="h5" gutterBottom>О этапе</Typography>
<Typography paragraph>
Здесь можно разместить подробную информацию о формате этапа, правилах,
требованиях к участникам и т.д.
</Typography>
{isRegistrationClosed && (
<Alert severity="info" sx={{my: 3}}>
Регистрация откроется позже. Следите за обновлениями!
</Alert>
)}
{isRegistrationOpen && stage.registrationLink && (
<Button
variant="contained"
color="success"
href={stage.registrationLink}
target="_blank"
startIcon={<DownloadIcon/>}
sx={{mt: 3}}
>
Зарегистрироваться на этап
</Button>
)}
</Box>
)}
{activeTab === 'classes' && (
<Box>
<Tabs
value={activeClassTab}
onChange={(e, newValue) => setActiveClassTab(newValue)}
variant="scrollable"
>
{Object.keys(participants).map((className, index) => (
<Tab key={className} label={className} value={index}/>
))}
</Tabs>
{Object.entries(participants).map(
([className, classParticipants], index) =>
index === activeClassTab && (
<Box key={className} sx={{mt: 3}}>
<Typography variant="h6">{className}</Typography>
<Table size="small">
<TableHead>
<TableRow>
<TableCell></TableCell>
<TableCell>Участник</TableCell>
</TableRow>
</TableHead>
<TableBody>
{classParticipants.map((p) => (
<TableRow
key={p.id}
sx={{
backgroundColor: p.isReserve ? 'grey.100' : 'inherit'
}}
>
<TableCell>{p.number}</TableCell>
<TableCell>
{
<TableCell>
{p.name}
{p.isReserve && (
<Typography variant="caption" color="text.secondary"
sx={{ml: 1}}>
(резерв)
</Typography>
)}
</TableCell>
}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{/* Индикатор заполненности класса */}
<Box sx={{mt: 2, display: 'flex', alignItems: 'center', gap: 1}}>
<Typography variant="body2" color="text.secondary">
Зарегистрировано: {classParticipants.length} / {maxParticipantsPerClass}
</Typography>
{classParticipants.length >= maxParticipantsPerClass && (
<Chip
label="Набор закрыт"
color="warning"
size="small"
/>
)}
</Box>
{/* Кнопка регистрации (только если открыт приём) */}
{isRegistrationOpen && classParticipants.length < maxParticipantsPerClass && (
<Button
variant="outlined"
startIcon={<DownloadIcon/>}
sx={{mt: 2}}
onClick={() => alert('Переход на форму регистрации')}
>
Зарегистрироваться в {className}
</Button>
)}
</Box>
))
}
</Box>
)}
{activeTab === 'events' && (
<Box>
<Tabs
value={activeClassTab}
onChange={(e, newValue) => setActiveClassTab(newValue)}
variant="scrollable"
>
<Tab label="Список участников" value={0}/>
{stage.hasGeneralQualification ? (
<Tab label="Общая квалификация" value={1}/>
) : (
Object.keys(participants).map((className, idx) => (
<Tab key={className} label={`Квалификация ${className}`} value={idx + 1}/>
))
)}
{/* Гонки (по количеству из настроек этапа) */}
{[...Array(stage.raceCount || 1)].map((_, raceIdx) => (
<Tab
key={raceIdx}
label={`Гонка ${raceIdx + 1}`}
value={stage.hasGeneralQualification ? raceIdx + 2 : raceIdx + 1 + Object.keys(participants).length}
/>
))}
</Tabs>
{/* Контент вкладок событий */}
{activeClassTab === 0 && (
<Box sx={{mt: 3}}>
<Typography variant="h6">Список участников</Typography>
{/* Здесь можно повторить таблицу участников из вкладки "Классы" */}
<Table size="small">
<TableHead>
<TableRow>
<TableCell></TableCell>
<TableCell>Участник</TableCell>
<TableCell>Класс</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.entries(participants).flatMap(([className, classParticipants]) =>
classParticipants.map(p => (
<TableRow key={p.id}>
<TableCell>{p.number}</TableCell>
<TableCell>{p.name}</TableCell>
<TableCell>{className}</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</Box>
)}
{stage.hasGeneralQualification && activeClassTab === 1 && (
<Box sx={{mt: 3}}>
<Typography variant="h6">Общая квалификация</Typography>
<Typography paragraph>
Здесь отображаются результаты общей квалификации.
</Typography>
{/* Место для таблицы результатов */}
</Box>
)}
{!stage.hasGeneralQualification &&
activeClassTab > 0 &&
activeClassTab <= Object.keys(participants).length && (
<Box sx={{mt: 3}}>
<Typography variant="h6">
Квалификация {Object.keys(participants)[activeClassTab - 1]}
</Typography>
<Typography paragraph>
Результаты квалификации для выбранного класса.
</Typography>
{/* Место для таблицы результатов */}
</Box>
)}
{activeClassTab >= (stage.hasGeneralQualification ? 2 : Object.keys(participants).length + 1) && (
<Box sx={{mt: 3}}>
<Typography
variant="h6">Гонка {activeClassTab - (stage.hasGeneralQualification ? 1 : Object.keys(participants).length)}</Typography>
<Typography paragraph>
Результаты гонки.
</Typography>
{/* Место для таблицы результатов */}
</Box>
)}
</Box>
)}
{/* Действия для завершённого этапа */}
{isCompleted && (
<Box sx={{mt: 4, textAlign: 'right'}}>
<Button
variant="contained"
startIcon={<PrintIcon/>}
onClick={() => window.print()}
>
Печать результатов
</Button>
</Box>
)}
</Container>
);
};
export default StagePage;

View File

@@ -0,0 +1,230 @@
import React, { useState, useEffect } from 'react';
import {
Container,
Typography,
Paper,
Table,
TableHead,
TableRow,
TableCell,
TableBody,
TableContainer,
Select,
MenuItem,
InputLabel,
FormControl,
Box,
Pagination,
Divider, Chip
} from '@mui/material';
import { Sort as SortIcon } from '@mui/icons-material';
// Моковые данные этапов
const MOCK_STAGES = [
{
id: 1,
title: 'SWC Зимний чемпионат',
stage: '2й этап',
date: '2026-02-08',
class: 'Юниоры',
status: 'Идёт',
},
{
id: 2,
title: 'Honda Winter Cup',
stage: '1й этап',
date: '2026-01-31',
class: 'Pro',
status: 'Регистрация открыта',
},
{
id: 3,
title: 'Кубок Покровска (онлайн)',
stage: '1й этап',
date: '2026-02-01',
class: 'Симулятор A',
status: 'Предрегистрация',
},
{
id: 4,
title: 'Гран-при Урала',
stage: 'Финальный этап',
date: '2026-03-15',
class: 'Взрослые',
status: 'Предрегистрация',
},
{
id: 5,
title: 'Открытый кубок Москвы',
stage: 'Квалификационный раунд',
date: '2026-01-20',
class: 'Amateur',
status: 'Завершено',
},
// Добавим ещё для демонстрации пагинации
{ id: 6, title: 'Этап 6', stage: 'Тест', date: '2026-04-01', class: 'Pro', status: 'Регистрация открыта' },
{ id: 7, title: 'Этап 7', stage: 'Тест', date: '2026-05-01', class: 'Юниоры', status: 'Идёт' },
{ id: 8, title: 'Этап 8', stage: 'Тест', date: '2026-06-01', class: 'Взрослые', status: 'Предрегистрация' },
];
const StagesPage = () => {
const [page, setPage] = useState(1);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [sortOrder, setSortOrder] = useState('asc');
const [filteredStages, setFilteredStages] = useState([]);
useEffect(() => {
let sorted = [...MOCK_STAGES];
sorted.sort((a, b) => {
const dateA = new Date(a.date);
const dateB = new Date(b.date);
return sortOrder === 'asc' ? dateA - dateB : dateB - dateA;
});
setFilteredStages(sorted);
}, [sortOrder]);
const handlePageChange = (event, newPage) => {
setPage(newPage);
};
const handleRowsPerPageChange = (event) => {
setRowsPerPage(Number(event.target.value));
setPage(1);
};
const currentStages = filteredStages.slice(
(page - 1) * rowsPerPage,
page * rowsPerPage
);
// Обработчик клика по строке
const handleRowClick = (stage) => {
// Здесь можно:
// - перенаправить на страницу этапа: navigate(`/stages/${stage.id}`)
// - открыть модалку с деталями
// - показать alert (пример ниже)
alert(`
Этап: ${stage.title}
Дата: ${new Date(stage.date).toLocaleDateString('ru-RU')}
Статус: ${stage.status}
Описание: ${stage.description}
`);
};
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Typography variant="h4" gutterBottom>
Этапы соревнований
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 3 }}>
<FormControl size="small">
<InputLabel>Сортировка</InputLabel>
<Select
value={sortOrder}
onChange={(e) => setSortOrder(e.target.value)}
startAdornment={<SortIcon sx={{ ml: 1 }} />}
>
<MenuItem value="asc">По возрастанию даты</MenuItem>
<MenuItem value="desc">По убыванию даты</MenuItem>
</Select>
</FormControl>
<FormControl size="small">
<InputLabel>Строк на странице</InputLabel>
<Select
value={rowsPerPage}
onChange={handleRowsPerPageChange}
>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={10}>10</MenuItem>
<MenuItem value={20}>20</MenuItem>
</Select>
</FormControl>
</Box>
<TableContainer component={Paper} variant="outlined">
<Table aria-label="таблица этапов">
<TableHead>
<TableRow>
<TableCell>Название</TableCell>
<TableCell>Этап</TableCell>
<TableCell>Дата</TableCell>
<TableCell>Класс</TableCell>
<TableCell>Статус</TableCell>
</TableRow>
</TableHead>
<TableBody>
{currentStages.map((stage) => (
<TableRow
key={stage.id}
sx={{
'&:hover': {
backgroundColor: 'action.hover',
cursor: 'pointer'
}
}}
onClick={() => handleRowClick(stage)}
>
<TableCell>{stage.title}</TableCell>
<TableCell>{stage.stage}</TableCell>
<TableCell>
{new Date(stage.date).toLocaleDateString('ru-RU')}
</TableCell>
<TableCell>{stage.class}</TableCell>
<TableCell>
<Chip
label={stage.status}
size="small"
color={
stage.status === 'Идёт'
? 'warning'
: stage.status === 'Регистрация открыта'
? 'success'
: stage.status === 'Предрегистрация'
? 'info'
: 'default'
}
sx={{
backgroundColor:
stage.status === 'Идёт'
? 'warning.dark'
: stage.status === 'Регистрация открыта'
? 'success.dark'
: stage.status === 'Предрегистрация'
? 'info.dark'
: 'grey.300',
color: 'white',
fontSize: '0.8rem',
}}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="body2" color="text.secondary">
Показано {currentStages.length} из {filteredStages.length} этапов
</Typography>
<Pagination
count={Math.ceil(filteredStages.length / rowsPerPage)}
page={page}
onChange={handlePageChange}
color="primary"
size="large"
/>
</Box>
<Divider sx={{ my: 4 }} />
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Все права защищены.
</Typography>
</Container>
);
};
export default StagesPage;

View File

@@ -0,0 +1,169 @@
// src/pages/UserPage.jsx
import React, { useState } from 'react';
import {
Container,
Typography,
Tabs,
Tab,
Avatar,
Box,
Card,
CardContent,
List,
ListItem,
ListItemText,
Divider,
Button,
} from '@mui/material';
import { useParams } from 'react-router-dom';
const UserPage = () => {
const { userId } = useParams();
const [activeTab, setActiveTab] = useState(0);
// Пример данных пользователя (в реальном проекте — из API)
const user = {
id: userId,
name: 'Алексей Карпов',
avatar: '/images/user-avatar.jpg',
email: 'alex@kart-hall.ru',
phone: '+7 (999) 123-45-67',
joinDate: '2023-05-10',
totalRaces: 24,
bestTime: '01:23.450', // лучшее время на трассе
};
// История заездов
const races = [
{ id: 1, event: 'Кубок KartHall 2024', date: '2024-08-15', time: '01:25.120', place: 3 },
{ id: 2, event: 'Ночной заезд', date: '2024-09-01', time: '01:24.890', place: 1 },
// ...
];
// Активные бронирования
const bookings = [
{ id: 1, track: 'Картодром KartHall', date: '2024-10-10 18:00', status: 'подтверждено' },
{ id: 2, track: 'Виртуальная трасса "Формула У"', date: '2024-10-12 20:00', status: 'ожидает оплаты' },
];
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
{/* Шапка профиля */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 3, mb: 4 }}>
<Avatar src={user.avatar} sx={{ width: 80, height: 80 }} />
<Box>
<Typography variant="h5">{user.name}</Typography>
<Typography variant="body2" color="text.secondary">
Участник с {new Date(user.joinDate).toLocaleDateString('ru-RU')}
</Typography>
</Box>
</Box>
{/* Вкладки */}
<Tabs value={activeTab} onChange={(e, newValue) => setActiveTab(newValue)} sx={{ mb: 3 }}>
<Tab label="Профиль" value={0} />
<Tab label="Мои заезды" value={1} />
<Tab label="Бронирования" value={2} />
<Tab label="Настройки" value={3} />
</Tabs>
{/* Контент вкладок */}
{activeTab === 0 && (
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>Личная информация</Typography>
<List>
<ListItem>
<ListItemText primary="Email" secondary={user.email} />
</ListItem>
<Divider />
<ListItem>
<ListItemText primary="Телефон" secondary={user.phone} />
</ListItem>
<Divider />
<ListItem>
<ListItemText
primary="Всего заездов"
secondary={user.totalRaces}
/>
</ListItem>
<Divider />
<ListItem>
<ListItemText
primary="Лучшее время"
secondary={user.bestTime}
/>
</ListItem>
</List>
</CardContent>
</Card>
)}
{activeTab === 1 && (
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>История заездов</Typography>
<List>
{races.map((race) => (
<ListItem key={race.id} divider>
<ListItemText
primary={race.event}
secondary={`Дата: ${race.date} | Время: ${race.time} | Место: ${race.place}`}
/>
</ListItem>
))}
</List>
</CardContent>
</Card>
)}
{activeTab === 2 && (
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>Мои бронирования</Typography>
<List>
{bookings.map((booking) => (
<ListItem key={booking.id} divider>
<ListItemText
primary={booking.track}
secondary={`Дата: ${booking.date} | Статус: ${booking.status}`}
/>
{booking.status === 'ожидает оплаты' && (
<Button size="small" variant="outlined" color="warning">
Оплатить
</Button>
)}
</ListItem>
))}
</List>
</CardContent>
</Card>
)}
{activeTab === 3 && (
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>Настройки профиля</Typography>
<List>
<ListItem>
<Button variant="outlined">Сменить пароль</Button>
</ListItem>
<Divider />
<ListItem>
<Button variant="outlined">Настроить уведомления</Button>
</ListItem>
<Divider />
<ListItem>
<Button variant="outlined" color="error">
Удалить аккаунт
</Button>
</ListItem>
</List>
</CardContent>
</Card>
)}
</Container>
);
};
export default UserPage;

View File

@@ -1,43 +0,0 @@
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import * as React from "react";
import {useState} from "react";
import Typography from "@mui/material/Typography";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
export function BarCreateModal({open, setOpen, create, id}) {
const [value, setValue] = useState("");
return (
<Dialog fullWidth={true}
open={open} onClose={() => setOpen(false)}
sx={{
'& .MuiDialog-paper': {
margin: '8px',
},
'& .MuiPaper-root': {
width: 'calc(100% - 16px)',
}
}}>
<DialogTitle>
<Typography>Создать список</Typography>
</DialogTitle>
<DialogContent>
<TextField sx={{width: '75%'}}
label={<Typography pt={'4px'}>
Название списка</Typography>} variant='outlined'
value={!value ? "" : value}
onChange={(e) => setValue(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => {
create(id, value);
setValue("");
}}>Создать</Button>
</DialogActions>
</Dialog>
)
}

View File

@@ -26,7 +26,7 @@ export function IngredientCard({row, value, infoHandler, changeHandler}) {
<IconButton size='small' onClick={() => infoHandler(row)}> <IconButton size='small' onClick={() => infoHandler(row)}>
<InfoRoundedIcon/> <InfoRoundedIcon/>
</IconButton> </IconButton>
<IconButton size='small' href={`${paths.bar.ingredientEdit}?id=${row.id}`}> <IconButton size='small' href={`${paths.stg.stages}?id=${row.id}`}>
<EditIcon/> <EditIcon/>
</IconButton> </IconButton>
</Stack> </Stack>

View File

@@ -0,0 +1,82 @@
import {DateCalendar} from "@mui/x-date-pickers/DateCalendar";
import {Paper} from "@mui/material";
import React from "react";
import Badge from "@mui/material/Badge";
import {PickersDay} from "@mui/x-date-pickers/PickersDay";
import dayjs from "dayjs";
const DayRenderer = (params) => {
const {stagesByDate = [], day, outsideCurrentMonth, ...other} = params;
const dayKey = params.day.date() + "-" + params.day.month();
const events = stagesByDate[dayKey] || [];
const isStage = events.length > 0;
return (
<Badge
key={params.day.toString()}
overlap="circular"
badgeContent={isStage ? '🏆' : undefined}
sx={{color: 'var(--mui-palette-text-primary)'}}
>
<PickersDay {...other} outsideCurrentMonth={outsideCurrentMonth} day={day}
// disabled
sx={{pointerEvents: 'none'}}/>
</Badge>
);
}
const Calendar = ({viewDate, setViewDate, stagesByDate}) => {
return (
<Paper
variant="outlined"
sx={{
borderRadius: 2,
boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
}}
>
<DateCalendar
defaultValue={dayjs()}
onMonthChange={(newValue) => {
if (newValue.month() !== viewDate.month) {
setViewDate(newValue);
}
}}
showDaysOutsideCurrentMonth
sx={{
height: '100%',
'.MuiDayCalendar-dayButton': {
minHeight: {xs: 80, sm: 100},
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
p: 1,
},
'.MuiPickersDay-root': {
fontSize: {xs: '1rem', sm: '1.1rem'},
},
'&.MuiPickersDay-root[data-selected="true"]': {
backgroundColor: 'primary.secondary',
color: 'white',
},
'&.MuiPickersDay-root:has(.event-chip)': {
border: '2px solid',
borderColor: 'primary.main',
},
}}
slots={{
day: DayRenderer
}}
slotProps={{
day: {
stagesByDate
}
}}
/>
</Paper>
)
}
export default Calendar;

View File

@@ -0,0 +1,57 @@
import {Box, useMediaQuery, useTheme} from "@mui/material";
import React, {useState} from "react";
import {CHAMPIONSHIP_STAGES} from "../../data/constants";
import Calendar from "./Calendar";
import MobileCalendarStageList from "./MobileCalendarStageList";
import DesktopCalendarStageList from "./DesktopCalendarStageList";
import dayjs from "dayjs";
export const CalendarContent = ({selectedClass}) => {
const [viewDate, setViewDate] = useState(dayjs()); // Дата для отображения месяца
const [openDrawer, setOpenDrawer] = useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
// Фильтрованные этапы для текущего месяца/класса
//todo: change from api
const filteredStages = CHAMPIONSHIP_STAGES.filter((stage) => {
const stageDate = new Date(stage.date);
const isSameMonth = stageDate.getMonth() === viewDate.month();
const isSameYear = stageDate.getFullYear() === viewDate.year();
const classMatch = selectedClass === 'Все' || stage.class === selectedClass;
return isSameMonth && isSameYear && classMatch;
});
// Группируем этапы по дате
const stagesByDate = filteredStages.reduce((acc, stage) => {
const days = dayjs(stage.date);
const dayKey = days.date() + "-" + days.month();
acc[dayKey] = acc[dayKey] || [];
acc[dayKey].push(stage);
return acc;
}, {});
return (
<>
{/* Основной контент */}
<Box sx={{
display: 'grid',
gridTemplateColumns: {xs: '1fr', md: '2fr 1fr'},
gap: {xs: 2, md: 4},
width: '100%',
maxWidth: 1400,
mx: 'auto',
mt: 2,
}}>
{/* Календарь */}
<Calendar viewDate={viewDate} setViewDate={setViewDate} stagesByDate={stagesByDate}/>
{/* Список этапов (только на десктопе) */}
{!isMobile && (<DesktopCalendarStageList filteredStages={filteredStages} viewDate={viewDate}/>)}
</Box>
<MobileCalendarStageList isMobile={isMobile} openDrawer={openDrawer} setOpenDrawer={setOpenDrawer}
filteredStages={filteredStages} viewDate={viewDate}/>
</>
);
}

View File

@@ -0,0 +1,94 @@
import {Box, Chip, ListItemButton, Typography} from "@mui/material";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import React from "react";
import {Link} from 'react-router-dom';
const CalendarDrawerContent = ({filteredStages, viewDate}) => {
return (
<Box sx={{p: 3, minWidth: 280}}>
<Typography variant="h6" gutterBottom>
Этапы на{' '}
{viewDate.format('MMMM YYYY')}
</Typography>
{/*todo: убрать этот блок, если не понадобиться кнопка для отображения пустых месяцев*/}
{filteredStages.length === 0 ? (
<Typography color="text.secondary" sx={{mt: 2}}>
Нет этапов в этом месяце
</Typography>
) : (
<List sx={{mt: 2}}>
{filteredStages.map((stage) => (
<ListItem
key={stage.id}
sx={{
mb: 1,
borderBottom: '1px solid',
borderColor: 'divider',
display: 'flex',
width: '100%',
// '&:hover': {
// backgroundColor: 'action.selected',
// transform: 'translateY(-2px)',
// boxShadow: '0 4px 8px rgba(0,0,0,0.1)',
// }
}} >
<ListItemButton component={Link} to={`/stages/${stage.id}`}
// style={{textDecoration: 'none'}}
sx={{
display: 'flex',
alignItems: 'center',
width: '100%',
px: 1,
py: 1.5,
borderRadius: 2,
'&:hover': {
// backgroundColor: 'action.selected',
transform: 'translateY(-2px)',
boxShadow: '0 4px 8px rgba(0,0,0,0.1)',
}
// Убираем hover здесь — он уже на ListItem
// transform: 'translateY(-2px)',
}}
key={stage.id}>
<Box
width='100%'
sx={{
flexGrow: 1,
px: 1,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
}}
>
<Typography variant="subtitle1" fontWeight="bold" color={'text.primary'}>
{stage.title}
</Typography>
<Typography variant="body2" color="text.secondary">
{stage.stage} · {stage.class}
</Typography>
<Box sx={{mt: 0.5}}>
<Chip
label={stage.status}
size="small"
color={
stage.status === 'Идёт'
? 'warning'
: stage.status === 'Регистрация открыта'
? 'success'
: 'info'
}
sx={{fontSize: '0.8rem'}}
/>
</Box>
</Box>
</ListItemButton>
</ListItem>
))}
</List>
)}
</Box>
)
}
export default CalendarDrawerContent;

View File

@@ -0,0 +1,51 @@
import {Box, Typography} from "@mui/material";
import {CalendarToday as CalendarIcon} from "@mui/icons-material";
import React from "react";
const CalendarHeader = (selectedClass, setSelectedClass) => {
// const [showFilters, setShowFilters] = useState(false);
return (
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 4,
flexWrap: 'wrap',
gap: 2
}}>
<Box sx={{display: 'flex', alignItems: 'center', gap: 1}}>
<CalendarIcon color="primary"/>
<Typography variant="h4">Календарь чемпионатов</Typography>
</Box>
{/* Фильтры */}
{/*<Box sx={{display: 'flex', gap: 2, flexWrap: 'wrap'}}>*/}
{/* <Button*/}
{/* variant="outlined"*/}
{/* // startIcon={<FilterIcon/>}*/}
{/* onClick={() => setShowFilters(!showFilters)}*/}
{/* size="small"*/}
{/* >*/}
{/* Фильтры*/}
{/* </Button>*/}
{/* {showFilters && (*/}
{/* <FormControl size="small" sx={{minWidth: 120}}>*/}
{/* <InputLabel>Класс</InputLabel>*/}
{/* <Select value={selectedClass} defaultValue={'Все'} onChange={(e) => setSelectedClass(e.target.value)}>*/}
{/* {['Все', 'Юниоры', 'Взрослые', 'Богатыри', '35+', 'Pro', 'Amateur', 'Симулятор A', 'Симулятор B'].map(*/}
{/* (cls) => (*/}
{/* <MenuItem key={cls} value={cls}>*/}
{/* {cls}*/}
{/* </MenuItem>*/}
{/* )*/}
{/* )}*/}
{/* </Select>*/}
{/* </FormControl>*/}
{/* )}*/}
{/*</Box>*/}
</Box>
)
}
export default CalendarHeader;

View File

@@ -0,0 +1,106 @@
import {Box, Chip, Paper, Typography} from "@mui/material";
import {Link} from "react-router-dom";
import React from "react";
const DesktopCalendarStageList = ({filteredStages, viewDate}) => {
return (
<Box sx={{height: '100%', display: 'flex', flexDirection: 'column'}}>
<Paper
variant="outlined"
sx={{
borderRadius: 2,
flexGrow: 1,
display: 'flex',
flexDirection: 'column',
boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
}}
>
<Box sx={{p: 3}}>
<Typography variant="h6" gutterBottom>
Этапы на{' '}
{viewDate.format('MMMM YYYY')}
</Typography>
{filteredStages.length === 0 ? (
<Typography color="text.secondary" sx={{my: 2}}>
Нет этапов в выбранном периоде
</Typography>
) : (
filteredStages.map((stage) => (
<Link
to={`/stages/${stage.id}`}
style={{textDecoration: 'none'}}
key={stage.id}
>
<Box
sx={{
p: 2.5,
borderRadius: 2,
backgroundColor: 'action.hover',
mb: 2,
transition: 'all 0.2s ease',
'&:hover': {
backgroundColor: 'action.selected',
transform: 'translateY(-2px)',
boxShadow: '0 4px 8px rgba(0,0,0,0.1)',
},
}}
>
<Typography
variant="subtitle1"
fontWeight="bold"
color="text.primary"
noWrap
sx={{mb: 0.5}}
>
{stage.title}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{mb: 1}}>
{stage.stage} · {stage.class}
</Typography>
<Box sx={{display: 'flex', gap: 1, flexWrap: 'wrap'}}>
<Chip
label={stage.status}
size="small"
color={
stage.status === 'Идёт'
? 'warning'
: stage.status === 'Регистрация открыта'
? 'success'
: 'info'
}
sx={{
backgroundColor:
stage.status === 'Идёт'
? 'warning.dark'
: stage.status === 'Регистрация открыта'
? 'success.dark'
: 'info.dark',
color: 'white',
fontWeight: 500,
fontSize: '0.8rem',
}}
/>
</Box>
<Typography
variant="body2"
color="text.secondary"
sx={{mt: 1.5}}
>
{new Date(stage.date).toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'long',
weekday: 'short',
})}
</Typography>
</Box>
</Link>
))
)}
</Box>
</Paper>
</Box>
)
}
export default DesktopCalendarStageList;

View File

@@ -0,0 +1,43 @@
import {Box, Button, Drawer} from "@mui/material";
import {CalendarToday as CalendarIcon} from "@mui/icons-material";
import React from "react";
import CalendarDrawerContent from "./CalendarDrawerContent";
const MobileCalendarStageList = ({isMobile, openDrawer, setOpenDrawer, filteredStages, viewDate}) => {
if (!isMobile || filteredStages.length === 0) {
return null;
}
return (
<>
{/* Drawer для мобильных */}
<Drawer
anchor="bottom"
open={openDrawer}
onClose={() => setOpenDrawer(false)}
PaperProps={{sx: {borderRadius: '16px 16px 0 0'}}}
>
<CalendarDrawerContent filteredStages={filteredStages} viewDate={viewDate}/>
</Drawer>
{/* Кнопка для открытия drawer на мобильных */}
<Box sx={{position: 'fixed', bottom: 80, right: 24}}>
<Button
variant="contained"
color="primary"
size="large"
onClick={() => setOpenDrawer(true)}
startIcon={<CalendarIcon/>}
sx={{
boxShadow: 3,
'&:hover': {boxShadow: 4},
borderRadius: 24,
}}
>
Посмотреть этапы
</Button>
</Box>
</>
)
}
export default MobileCalendarStageList;

View File

@@ -0,0 +1,26 @@
import {Card, Grid} from "@mui/material";
import React from "react";
import ChampionshipCardContent from "./ChampionshipCardContent";
import ChampionshipCardAction from "./ChampionshipCardAction";
const ChampionshipCard = ({champ}) => {
return (
<Grid item xs={12} sm={6} md={4} key={champ.id}>
<Card variant="outlined" sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between', // Растягивает содержимое, прижимает actions вниз
transition: 'transform 0.2s',
'&:hover': {
transform: 'scale(1.02)'
}
}}>
<ChampionshipCardContent champ={champ}/>
<ChampionshipCardAction champId={champ.id}/>
</Card>
</Grid>
)
}
export default ChampionshipCard;

View File

@@ -0,0 +1,35 @@
import {Box, CardActions, IconButton} from "@mui/material";
import {Edit as EditIcon} from "@mui/icons-material";
import React from "react";
import {Link} from "react-router-dom";
import Button from "@mui/material/Button";
const ChampionshipCardAction = ({champId}) => {
return (
<CardActions sx={{justifyContent: 'flex-start', p: 2}}>
{/* Действия */}
<Box sx={{display: 'flex', gap: 1}}>
<Button
component={Link}
to={`/championships/${champId}`}
size="small"
color="primary"
variant="contained"
>
Подробнее
</Button>
<IconButton
component={Link}
to={`/championships/${champId}/edit`}
size="small"
color="secondary"
title="Редактировать"
>
<EditIcon fontSize="small"/>
</IconButton>
</Box>
</CardActions>
)
}
export default ChampionshipCardAction;

View File

@@ -0,0 +1,62 @@
import {Box, CardContent, Table, TableBody, TableCell, TableRow, Tooltip, Typography} from "@mui/material";
import React from "react";
const ChampionshipCardContent = ({champ}) => {
return (
<CardContent>
<Box
sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'start', mb: 2}}>
<Box>
<Typography variant="h6">
{champ.title}
</Typography>
<Tooltip title={champ.status}>
<Typography
variant="caption"
sx={{
backgroundColor: champ.status === 'Идёт' ? 'warning.main' :
champ.status === 'Регистрация открыта' ? 'success.main' : 'info.main',
color: 'white',
px: 1,
borderRadius: 1,
whiteSpace: 'nowrap'
}}
>
{champ.status}
</Typography>
</Tooltip>
<Typography variant="subtitle2" color="text.secondary">
{champ.season}
</Typography>
</Box>
</Box>
{/* Таблица с основными данными */}
<Table size="small" sx={{mt: 2}}>
<TableBody>
<TableRow>
<TableCell variant="head">Этапы</TableCell>
<TableCell>{champ.stages}</TableCell>
</TableRow>
<TableRow>
<TableCell variant="head">Классы</TableCell>
<TableCell>
{champ.classes.join(', ')}
</TableCell>
</TableRow>
<TableRow>
<TableCell variant="head">Начало</TableCell>
<TableCell>{champ.startDate}</TableCell>
</TableRow>
<TableRow>
<TableCell variant="head">Конец</TableCell>
<TableCell>{champ.endDate}</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
)
}
export default ChampionshipCardContent;

View File

@@ -0,0 +1,25 @@
import {Box, Button, Typography} from "@mui/material";
import {Add as AddIcon} from "@mui/icons-material";
import React from "react";
const ChampionshipHeader = () => {
return (
<Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 4}}>
<Typography variant="h4">
Все чемпионаты
</Typography>
<Button
variant="contained"
size={'small'}
color="primary"
startIcon={<AddIcon/>}
href="/championships/create"
sx={{px: 3}}
>
Создать чемпионат
</Button>
</Box>
)
}
export default ChampionshipHeader;

View File

@@ -0,0 +1,32 @@
import {Button, Grid, Paper, Typography} from "@mui/material";
import React from "react";
import ChampionshipCard from "./ChampionshipCard";
import {CHAMPIONSHIP_STAGES} from "../../data/constants";
const ChampionshipsList = () => {
return (
<>
<Grid container spacing={4}>
{CHAMPIONSHIP_STAGES.map((champ) => <ChampionshipCard champ={champ}/>)}
</Grid>
{/* Сообщение, если чемпионатов нет */}
{CHAMPIONSHIP_STAGES.length === 0 && (
<Paper sx={{textAlign: 'center', py: 8}}>
<Typography color="text.secondary">
Пока нет ни одного чемпионата. Создайте первый!
</Typography>
<Button
variant="outlined"
sx={{mt: 2}}
href="/championships/create"
>
Создать чемпионат
</Button>
</Paper>
)}
</>
)
}
export default ChampionshipsList;

View File

@@ -0,0 +1,14 @@
import {Divider, Typography} from "@mui/material";
import React from "react";
import {FOOTER_MESSAGE} from "../../data/constants";
export function Footer() {
return (
<>
<Divider sx={{my: 4}}/>
<Typography variant="body2" color="text.secondary" align="center" sx={{my:2}}>
{FOOTER_MESSAGE}
</Typography>
</>
);
}

View File

@@ -1,49 +1,41 @@
import {styled, useColorScheme} from "@mui/material/styles"; import {styled, useColorScheme} from "@mui/material/styles";
import Switch from "@mui/material/Switch"; import Switch from "@mui/material/Switch";
import React from "react"; import React from "react";
import Box from "@mui/material/Box"; import ListItemIcon from "@mui/material/ListItemIcon";
import Typography from "@mui/material/Typography"; import LightModeIcon from '@mui/icons-material/LightMode';
export function ThemeSwitch() { export function ThemeSwitch() {
const {mode, setMode} = useColorScheme(); const {mode, setMode} = useColorScheme();
return ( return (
<Box <>
sx={{ {/*Box*/}
alignItems: 'center', {/*// sx={{*/}
// backgroundColor: 'var(--mui-palette-neutral-950)', {/*// // alignItems: 'center',*/}
border: '1px solid var(--mui-palette-neutral-700)', {/*// // backgroundColor: 'var(--mui-palette-neutral-950)',*/}
borderRadius: '12px', {/*// // border: '1px solid var(--mui-palette-neutral-700)',*/}
cursor: 'pointer', {/*// // borderRadius: '12px',*/}
display: 'flex', {/*// // cursor: 'pointer',*/}
p: '4px 12px', {/*// // display: 'flex',*/}
}} {/*// // p: '4px 12px',*/}
> {/*// }}*/}
{/*// >*/}
<ListItemIcon>
<LightModeIcon fontSize="small"/>
</ListItemIcon>
<StyledSwitch <StyledSwitch
checked={mode === 'dark'} checked={mode === 'dark'}
onChange={(e) => setMode(e.target.checked ? 'dark' : 'light')} onChange={(e) => setMode(e.target.checked ? 'dark' : 'light')}
inputProps={{'aria-label': 'controlled'}} inputProps={{'aria-label': 'controlled'}}
/> />
<Box sx={{flex: '1 1 auto'}}> </>
<Typography color="inherit" variant="subtitle1">
{(mode === 'dark' ? "Темная " : "Светлая ") + "тема"}
</Typography>
</Box>
</Box>
) )
} }
const StyledSwitch = styled(Switch)(({theme}) => ({ const StyledSwitch = styled(Switch)(({theme}) => ({
width: 62,
height: 34,
padding: 7,
'& .MuiSwitch-switchBase': { '& .MuiSwitch-switchBase': {
margin: 1,
padding: 0,
transform: 'translateX(6px)',
'&.Mui-checked': { '&.Mui-checked': {
color: '#fff', color: '#fff',
transform: 'translateX(22px)',
'& .MuiSwitch-thumb:before': { '& .MuiSwitch-thumb:before': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent( backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent(
'#fff', '#fff',
@@ -51,24 +43,22 @@ const StyledSwitch = styled(Switch)(({theme}) => ({
}, },
'& + .MuiSwitch-track': { '& + .MuiSwitch-track': {
opacity: 1, opacity: 1,
backgroundColor: theme.palette.mode === 'dark' ? '#8796A5' : '#aab4be', backgroundColor: theme.palette.mode === 'dark' ? '#c5bebe' : '#aab4be',
}, },
}, },
}, },
'& .MuiSwitch-thumb': { '& .MuiSwitch-thumb': {
backgroundColor: theme.palette.mode === 'dark' ? '#003892' : '#001e3c', backgroundColor: theme.palette.mode === 'dark' ? '#8f8f8f' : '#424242',
width: 32,
height: 32,
'&::before': { '&::before': {
content: "''", content: "''",
position: 'absolute', position: 'absolute',
width: '100%', width: '95%',
height: '100%', height: '95%',
left: 0, left: 0,
top: 0, top: 0,
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
backgroundPosition: 'center', backgroundPosition: 'center',
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent( backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 18 18"><path fill="${encodeURIComponent(
'#fff', '#fff',
)}" d="M9.305 1.667V3.75h1.389V1.667h-1.39zm-4.707 1.95l-.982.982L5.09 6.072l.982-.982-1.473-1.473zm10.802 0L13.927 5.09l.982.982 1.473-1.473-.982-.982zM10 5.139a4.872 4.872 0 00-4.862 4.86A4.872 4.872 0 0010 14.862 4.872 4.872 0 0014.86 10 4.872 4.872 0 0010 5.139zm0 1.389A3.462 3.462 0 0113.471 10a3.462 3.462 0 01-3.473 3.472A3.462 3.462 0 016.527 10 3.462 3.462 0 0110 6.528zM1.665 9.305v1.39h2.083v-1.39H1.666zm14.583 0v1.39h2.084v-1.39h-2.084zM5.09 13.928L3.616 15.4l.982.982 1.473-1.473-.982-.982zm9.82 0l-.982.982 1.473 1.473.982-.982-1.473-1.473zM9.305 16.25v2.083h1.389V16.25h-1.39z"/></svg>')`, )}" d="M9.305 1.667V3.75h1.389V1.667h-1.39zm-4.707 1.95l-.982.982L5.09 6.072l.982-.982-1.473-1.473zm10.802 0L13.927 5.09l.982.982 1.473-1.473-.982-.982zM10 5.139a4.872 4.872 0 00-4.862 4.86A4.872 4.872 0 0010 14.862 4.872 4.872 0 0014.86 10 4.872 4.872 0 0010 5.139zm0 1.389A3.462 3.462 0 0113.471 10a3.462 3.462 0 01-3.473 3.472A3.462 3.462 0 016.527 10 3.462 3.462 0 0110 6.528zM1.665 9.305v1.39h2.083v-1.39H1.666zm14.583 0v1.39h2.084v-1.39h-2.084zM5.09 13.928L3.616 15.4l.982.982 1.473-1.473-.982-.982zm9.82 0l-.982.982 1.473 1.473.982-.982-1.473-1.473zM9.305 16.25v2.083h1.389V16.25h-1.39z"/></svg>')`,
}, },

View File

@@ -0,0 +1,24 @@
import {Fab} from "@mui/material";
import UpIcon from '@mui/icons-material';
import {blue} from "@mui/material/colors";
const UpButton = () => {
return (
<Fab sx={{
alpha: '30%',
position: 'sticky',
left: 'calc(100% - 16px)',
bottom: '16px',
color: 'common.white',
bgcolor: blue[600],
'&:hover': {
bgcolor: blue[600],
},
}}
onClick={() => window.window.scrollTo(0, 0)}
aria-label='Expand'
color='inherit'>
<UpIcon/>
</Fab>
)
}

View File

@@ -2,6 +2,8 @@ import * as React from 'react';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemIcon from '@mui/material/ListItemIcon';
import {User as UserIcon} from '@phosphor-icons/react/dist/ssr/User';
import {Link} from 'react-router-dom';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import MenuList from '@mui/material/MenuList'; import MenuList from '@mui/material/MenuList';
import Popover from '@mui/material/Popover'; import Popover from '@mui/material/Popover';
@@ -14,6 +16,8 @@ import {authClient} from "../../lib/clients/AuthClient";
import {useLocation} from "react-router-dom"; import {useLocation} from "react-router-dom";
import {useUser} from "../../hooks/useUser"; import {useUser} from "../../hooks/useUser";
import {paths} from "../../path"; import {paths} from "../../path";
import {ThemeSwitch} from "./ThemeSwitch";
import Stack from "@mui/material/Stack";
export function UserPopover({anchorEl, onClose, open}) { export function UserPopover({anchorEl, onClose, open}) {
const {checkSession} = useAuth(); const {checkSession} = useAuth();
@@ -55,18 +59,19 @@ export function UserPopover({anchorEl, onClose, open}) {
</Box> </Box>
<Divider/> <Divider/>
<MenuList disablePadding sx={{p: '8px', '& .MuiMenuItem-root': {borderRadius: 1}}}> <MenuList disablePadding sx={{p: '8px', '& .MuiMenuItem-root': {borderRadius: 1}}}>
{/*<MenuItem component={'a'} href={paths.dashboard.settings} onClick={onClose}>*/} {/*<MenuItem component={Link} href={paths.home} onClick={onClose}>*/}
{/* <ListItemIcon>*/} {/* <ListItemIcon>*/}
{/* <GearSixIcon fontSize="var(--icon-fontSize-md)"/>*/} {/* <SignInIcon fontSize="var(--icon-fontSize-md)"/>*/}
{/* </ListItemIcon>*/} {/* </ListItemIcon>*/}
{/* Настройки*/} {/* Настройки*/}
{/*</MenuItem>*/} {/*</MenuItem>*/}
{/*<MenuItem component={'a'} href={paths.dashboard.account} onClick={onClose}>*/}
{/* <ListItemIcon>*/} <MenuItem component={Link} to={`/users/${user.id}`} onClick={onClose}>
{/* <UserIcon fontSize="var(--icon-fontSize-md)"/>*/} <ListItemIcon>
{/* </ListItemIcon>*/} <UserIcon fontSize="var(--icon-fontSize-md)"/>
{/* Профиль*/} </ListItemIcon>
{/*</MenuItem>*/} Профиль
</MenuItem>
{!user.name ? <MenuItem onClick={() => window.location.replace(paths.auth.signIn)}> {!user.name ? <MenuItem onClick={() => window.location.replace(paths.auth.signIn)}>
<ListItemIcon> <ListItemIcon>
<SignInIcon fontSize="var(--icon-fontSize-md)"/> <SignInIcon fontSize="var(--icon-fontSize-md)"/>
@@ -80,6 +85,9 @@ export function UserPopover({anchorEl, onClose, open}) {
Выход Выход
</MenuItem> </MenuItem>
} }
<MenuItem sx={{'--mui-palette-action-hover': 'rgba(0, 0, 0, 0)'}}>
<ThemeSwitch/>
</MenuItem>
</MenuList> </MenuList>
</Popover> </Popover>
); );

View File

@@ -5,28 +5,30 @@ import {User as UserIcon} from '@phosphor-icons/react/dist/ssr/User';
import {Users as UsersIcon} from '@phosphor-icons/react/dist/ssr/Users'; import {Users as UsersIcon} from '@phosphor-icons/react/dist/ssr/Users';
import {XSquare} from '@phosphor-icons/react/dist/ssr/XSquare'; import {XSquare} from '@phosphor-icons/react/dist/ssr/XSquare';
import { import {
Basket, Buildings,
BookOpen, Calculator,
Books, Calendar,
CardsThree,
SteeringWheel,
Cheers, Cheers,
CoffeeBean, CoffeeBean,
Car,
Coins, Coins,
Martini, House,
Storefront, Trophy,
Users, Users
Wallet,
Calculator
} from "@phosphor-icons/react"; } from "@phosphor-icons/react";
export const navIcons = { export const navIcons = {
'menu': BookOpen, 'home': House,
'list': Books, 'championships': Trophy,
'storefront': Storefront, 'calendar': Calendar,
'wallet': Wallet, 'stages': SteeringWheel,
'cocktail': Martini, 'places': Buildings,
'rent': Car,
'visitors': Users, 'visitors': Users,
'orders': Cheers, 'orders': Cheers,
'basket': Basket,
'coins': Coins, 'coins': Coins,
'ingredients': CoffeeBean, 'ingredients': CoffeeBean,
'chart-pie': ChartPieIcon, 'chart-pie': ChartPieIcon,

View File

@@ -0,0 +1,19 @@
import Grid from "@mui/material/Grid";
import * as React from "react";
import AnnounceCard from "./AnnounceCard";
import {MOCK_STAGES} from "../../data/constants";
const AnnounceBlock = () => {
const stages = MOCK_STAGES.slice(0, 3);
return (
<Grid container spacing={4} sx={{mb: 6}}>
{stages.map((champ, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<AnnounceCard champ={champ}/>
</Grid>
))}
</Grid>
);
}
export default AnnounceBlock;

View File

@@ -0,0 +1,46 @@
import {Card, CardActions, CardContent} from "@mui/material";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import {Link} from "react-router-dom";
import * as React from "react";
import {Trophy} from "@phosphor-icons/react";
const AnnounceCard = ({champ}) => {
return (
<Card variant="outlined" sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between', // Растягивает содержимое, прижимает actions вниз
height: '100%',
transition: 'transform 0.2s',
'&:hover': {transform: 'scale(1.02)'}
}}>
<CardContent sx={{p:2, pb: 1}}>
<Box sx={{display: 'flex', alignItems: 'center', mb: 2}}>
<Trophy/>
<Typography variant="h6" sx={{ml: 1}}>
{champ.title}
</Typography>
</Box>
<Typography color="text.secondary" sx={{mb: 1}}>
{champ.stage.name} {champ.date}
</Typography>
</CardContent>
<CardActions sx={{ justifyContent: 'flex-start', px: 2, pb: 2 }}>
<Button
component={Link}
variant="contained"
color="primary"
to={`/stages/${champ.stage.id}`}
sx={{mt: 2}}
>
Подробнее
</Button>
</CardActions>
</Card>
)
}
export default AnnounceCard;

View File

@@ -0,0 +1,34 @@
import * as React from "react";
import Typography from "@mui/material/Typography";
// Компонент таймера (упрощённый)
const CountdownTimer = ({targetDate}) => {
const [timeLeft, setTimeLeft] = React.useState({});
React.useEffect(() => {
const updateTimer = () => {
const now = new Date().getTime();
const distance = new Date(targetDate).getTime() - now;
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
setTimeLeft({days, hours, minutes, seconds});
};
const interval = setInterval(updateTimer, 1000);
updateTimer();
return () => clearInterval(interval);
}, [targetDate]);
return (
<Typography variant="h6" color="error" sx={{fontWeight: 'bold'}}>
До старта: {timeLeft.days}д {timeLeft.hours}ч {timeLeft.minutes}м {timeLeft.seconds}с
</Typography>
);
};
export default CountdownTimer;

View File

@@ -0,0 +1,44 @@
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import {Link} from "react-router-dom";
import {paths} from "../../path";
import * as React from "react";
const LastResult = () => {
// Результаты последнего этапа
const results = {
Юниоры: ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
Взрослые: ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
Богатыри: ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
'35+': ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
};
return (
<Box sx={{mb: 6}}>
<Typography variant="h5" sx={{mb: 3}}>
Итоги 1го этапа SWC (18.01.2026)
</Typography>
{Object.entries(results).map(([category, winners]) => (
<Box key={category} sx={{mb: 2}}>
<Typography variant="subtitle1" color="primary">
{category}:
</Typography>
<Typography color="text.secondary">
1 место: {winners[0]}, 2 место: {winners[1]}, 3 место: {winners[2]}
</Typography>
</Box>
))}
<Button
component={Link}
variant="outlined"
to={paths.stg.stages}
sx={{mt: 3}}
>
Все результаты
</Button>
</Box>
)
}
export default LastResult;

View File

@@ -0,0 +1,22 @@
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import * as React from "react";
import Button from "@mui/material/Button";
import CountdownTimer from "./CountdownTimer";
const NextStageTimer = () => {
const title = 'SWC Зимний чемпионат 20252026';
return (
<Box sx={{textAlign: 'center', mb: 6}}>
<Typography variant="h5" sx={{mb: 2}}>
Следующий этап "{title}":
</Typography>
<CountdownTimer targetDate="2026-02-08T09:00:00"/>
<Button variant="contained" color="secondary" sx={{mt:2}}>
Регистрация
</Button>
</Box>
)
}
export default NextStageTimer;

View File

@@ -0,0 +1,20 @@
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
const QuickActions = () => {
return (
<Box sx={{display: 'flex', flexWrap: 'wrap', gap: 2, mb: 6}}>
<Button variant="contained" color="secondary" href="/register">
Зарегистрироваться на этап
</Button>
<Button variant="outlined" href="/calendar">
Посмотреть календарь всех этапов
</Button>
<Button variant="outlined" href="/rules">
Правила гонок
</Button>
</Box>
)
}
export default QuickActions;

View File

@@ -0,0 +1,23 @@
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import * as React from "react";
import {RENT_BUTTON, RENT_MESSAGE, RENT_QUEST} from "../../data/constants";
const RentBlock = () => {
return (
<Box sx={{textAlign: 'center', my: 6}}>
<Typography variant="h5" sx={{mb: 2}}>
{RENT_QUEST}
</Typography>
<Typography color="text.secondary" sx={{mb: 3}}>
{RENT_MESSAGE}
</Typography>
<Button variant="contained" color="success" href="/rent">
{RENT_BUTTON}
</Button>
</Box>
)
}
export default RentBlock;

View File

@@ -0,0 +1,15 @@
import SponsorsCarousel from "./SponsorsCarousel";
import Typography from "@mui/material/Typography";
import * as React from "react";
const SponsorsBlock = () => {
return (
<>
<SponsorsCarousel/>
<Typography variant="caption" color="text.secondary" sx={{mb: 4}}>
Наши партнёры: поддержка чемпионатов и призов
</Typography>
</>
)
}
export default SponsorsBlock;

View File

@@ -0,0 +1,48 @@
import {Box, Avatar} from '@mui/material';
import Carousel from "react-material-ui-carousel";
import {sponsors} from "../../data/constants";
const SponsorsCarousel = () => {
// Дублируем логотипы для бесшовной прокрутки
const items = [...sponsors];
return (
<Box sx={{mb: 4, overflow: 'hidden'}}>
<Carousel
autoPlay
interval={3000} // смена каждые 3 сек
animation="slide" // плавный слайд
duration={800} // длительность анимации (мс)
stopOnHover={true} // не останавливать при наведении
indicators={false}
cycleNavigation // зациклить
infiniteLoop // бесконечная прокрутка
swipe // отключить свайп (если не нужен)
sx={{
'& .MuiBox-root': {p: 0, display: 'flex', alignItems: 'center'},
}}
>
{/* Генерируем слайды: каждый слайд — строка из 34 логотипов */}
{Array.from({length: Math.ceil(items.length / 3)}).map((_, slideIdx) => (
<Box key={slideIdx} sx={{display: 'flex', justifyContent: 'space-around', px: 2}}>
{items.slice(slideIdx * 3, slideIdx * 3 + 3).map((sponsor, idx) => (
<Avatar
key={idx}
src={sponsor.logo}
alt={sponsor.name}
sx={{
width: 300,
height: 150,
borderRadius: '6px',
mx: 2,
}}
/>
))}
</Box>
))}
</Carousel>
</Box>
);
};
export default SponsorsCarousel;

View File

@@ -0,0 +1,18 @@
import Typography from "@mui/material/Typography";
import * as React from "react";
import {WELCOME_MESSAGE_PRIME, WELCOME_MESSAGE_SECOND} from "../../data/constants";
const WelcomeBlock = () => {
return(
<>
<Typography variant="h4" gutterBottom>
{WELCOME_MESSAGE_PRIME}
</Typography>
<Typography variant="h6" color="text.secondary" gutterBottom sx={{mb: 4}}>
{WELCOME_MESSAGE_SECOND}
</Typography>
</>
)
}
export default WelcomeBlock

View File

@@ -8,6 +8,10 @@ import {List as ListIcon} from '@phosphor-icons/react/dist/ssr/List';
import {usePopover} from "../../hooks/usePopover"; import {usePopover} from "../../hooks/usePopover";
import {MobileNav} from "./MobileNav"; import {MobileNav} from "./MobileNav";
import {UserPopover} from "../core/UserPopover"; import {UserPopover} from "../core/UserPopover";
import Button from "@mui/material/Button";
import {renderNavItems} from "./NavItem";
import {navItems} from "../../navItems";
import {useLocation} from "react-router-dom";
// import Tooltip from "@mui/material/Tooltip"; // import Tooltip from "@mui/material/Tooltip";
// import {Badge} from "@mui/material"; // import {Badge} from "@mui/material";
// import {useAlert} from "../../hooks/useAlert"; // import {useAlert} from "../../hooks/useAlert";
@@ -15,12 +19,20 @@ import {UserPopover} from "../core/UserPopover";
export function MainNav() { export function MainNav() {
const [openNav, setOpenNav] = React.useState(false); const [openNav, setOpenNav] = React.useState(false);
const userPopover = usePopover(); const userPopover = usePopover();
const location = useLocation();
const pathname = location.pathname;
return ( return (
<> <>
<Box <Box
component="header" component="header"
sx={{ sx={{
'--MobileNav-background': 'var(--mui-palette-neutral-950)',
'--NavItem-color': 'var(--mui-palette-text-secondary)',
'--NavItem-active-color': 'var(--mui-palette-text-primary)',
'--NavItem-disabled-color': 'var(--mui-palette-neutral-200)',
'--NavItem-icon-color': 'var(--mui-palette-text-secondary)',
'--NavItem-icon-active-color': 'var(--mui-palette-text-primary)',
borderBottom: '1px solid var(--mui-palette-divider)', borderBottom: '1px solid var(--mui-palette-divider)',
backgroundColor: 'var(--mui-palette-background-paper)', backgroundColor: 'var(--mui-palette-background-paper)',
position: 'sticky', position: 'sticky',
@@ -32,9 +44,12 @@ export function MainNav() {
<Stack direction="row" spacing={3} <Stack direction="row" spacing={3}
sx={{alignItems: 'center', justifyContent: 'space-between', minHeight: '64px', px: 2}}> sx={{alignItems: 'center', justifyContent: 'space-between', minHeight: '64px', px: 2}}>
<Stack sx={{alignItems: 'center'}} direction="row" spacing={3}> <Stack sx={{alignItems: 'center'}} direction="row" spacing={3}>
<IconButton onClick={() => setOpenNav(true)} sx={{display: {xl: 'none'}}}> <IconButton onClick={() => setOpenNav(true)} sx={{display: {md: 'none'}}}>
<ListIcon/> <ListIcon/>
</IconButton> </IconButton>
<Box component="nav" sx={{flex: '1 1 auto', p: 1, display: {xs: 'none', md: 'flex'}}}>
{renderNavItems({items: navItems, pathname: pathname, direction: 'row'})}
</Box>
</Stack> </Stack>
<Stack sx={{alignItems: 'center'}} direction="row" spacing={2}> <Stack sx={{alignItems: 'center'}} direction="row" spacing={2}>
<Avatar onClick={userPopover.handleOpen} ref={userPopover.anchorRef} src="/assets/avatar.png" <Avatar onClick={userPopover.handleOpen} ref={userPopover.anchorRef} src="/assets/avatar.png"

View File

@@ -5,23 +5,22 @@ import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
export function renderNavItems({items = [], pathname}) { export function renderNavItems({items = [], pathname, direction}) {
const children = items.reduce((acc, curr) => { const children = items.reduce((acc, curr) => {
const {key, ...item} = curr; acc.push(<NavItem key={curr.name} pathname={pathname} {...curr} />);
acc.push(<NavItem key={key} pathname={pathname} {...item} />);
return acc; return acc;
}, []); }, []);
return ( return (
<Stack key={"stack-NavItem-key"} component="ul" spacing={1} sx={{listStyle: 'none', m: 0, p: 0}}> <Stack key={"stack-NavItem-key"} component="ul" spacing={1} sx={{listStyle: 'none', m: 0, p: 0}} direction={direction}>
{children} {children}
</Stack> </Stack>
); );
} }
function NavItem({disabled, external, href, icon, matcher, pathname, title}) { function NavItem({disabled, name, external, href, matcher, pathname, title}) {
const active = isNavItemActive({disabled, external, href, matcher, pathname}); const active = isNavItemActive({disabled, external, href, matcher, pathname});
const Icon = icon ? navIcons[icon] : null; const Icon = name ? navIcons[name] ? navIcons[name] : null : null;
return ( return (
<li> <li>
@@ -35,7 +34,7 @@ function NavItem({disabled, external, href, icon, matcher, pathname, title}) {
display: 'flex', display: 'flex',
flex: '0 0 auto', flex: '0 0 auto',
gap: 1, gap: 1,
p: '6px 16px', p: 0.5,
position: 'relative', position: 'relative',
textDecoration: 'none', textDecoration: 'none',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',

View File

@@ -7,15 +7,6 @@ import {navItems} from "../../navItems";
import React, {useEffect, useState} from "react"; import React, {useEffect, useState} from "react";
import {useLocation} from "react-router-dom"; import {useLocation} from "react-router-dom";
import {useUser} from "../../hooks/useUser"; import {useUser} from "../../hooks/useUser";
import Typography from "@mui/material/Typography";
function renderSpecialItems(items, label, pathname) {
return (
<Box>
{renderNavItems({items: items, pathname: pathname})}
</Box>
)
}
export function NavigationMenu() { export function NavigationMenu() {
const location = useLocation(); const location = useLocation();
@@ -23,17 +14,10 @@ export function NavigationMenu() {
const {user} = useUser(); const {user} = useUser();
const [items, setItems] = useState(null) const [items, setItems] = useState(null)
const userChild = navItems.filter((item) => !item.forBarmen && !item.forAdmin)
const barmenChild = navItems.filter((item) => item.forBarmen)
const adminChild = navItems.filter((item) => item.forAdmin)
useEffect(() => { useEffect(() => {
const role = !user ? "USER" : Object.keys(user).length === 0 ? "USER" : user.role
const newState = ( const newState = (
<Box component="nav" sx={{flex: '1 1 auto', p: '12px'}}> <Box component="nav" sx={{flex: '1 1 auto', p: '12px'}}>
{renderNavItems({items: userChild, pathname: pathname})} {renderNavItems({items: navItems, pathname: pathname, direction: 'column'})}
{role !== "USER" && renderSpecialItems(barmenChild, "Для бармена:", pathname)}
{role === "ADMIN" && renderSpecialItems(adminChild, "Для админа", pathname)}
</Box> </Box>
) )
setItems(newState) setItems(newState)
@@ -43,9 +27,6 @@ export function NavigationMenu() {
return ( return (
<> <>
{/*верхняя стопка*/} {/*верхняя стопка*/}
<Stack spacing={2} sx={{p: 2, height: '63px'}}>
<ThemeSwitch/>
</Stack>
<Divider sx={{borderColor: 'var(--mui-palette-neutral-700)'}}/> <Divider sx={{borderColor: 'var(--mui-palette-neutral-700)'}}/>
{/*меню навигации*/} {/*меню навигации*/}
{items} {items}

View File

@@ -1,19 +1,21 @@
import {Route, Routes} from "react-router-dom"; import {Route, Routes} from "react-router-dom";
import {paths} from "../path"; import {paths} from "../../path";
import {useAuth} from "../hooks/useAuth"; import {useAuth} from "../../hooks/useAuth";
import NotFoundPage from "./pages/notFound/NotFoundPage"; import NotFoundPage from "../../app/pages/notFound/NotFoundPage";
import {UserLayout} from "./layout/UserLayout"; import {UserLayout} from "../../app/layout/UserLayout";
import {HomeRedirect} from "./HomeRedirect"; import {PublicLayout} from "../../app/layout/PublicLayout";
import {PublicLayout} from "./layout/PublicLayout"; import LoginPage from "../../app/pages/auth/sign-in/loginPage";
import LoginPage from "./pages/auth/sign-in/loginPage"; import {TelegramCode} from "../../app/pages/auth/sign-in/telegram-code";
import {TelegramCode} from "./pages/auth/sign-in/telegram-code"; import {MenuPage} from "../../app/pages/home/MenuPage";
import {IngredientsPage} from "./pages/ingredients/IngredientsPage";
import {MenuPage} from "./pages/cocktails/MenuPage";
import {EditIngredientPage} from "./pages/ingredients/EditIngredientPage";
import {EditCocktailPage} from "./pages/cocktails/EditCocktailPage";
import {useEffect, useState} from "react"; import {useEffect, useState} from "react";
import {BarChangePage} from "./pages/BarChangePage"; import ChampionshipsPage from "../../app/pages/championship/ChampionshipsPage";
import {CalcPage} from "./pages/calc/CalcPage"; import CalendarPage from "../../app/pages/calendar/CalendarPage";
import StagesPage from "../../app/pages/stages/StagesPage";
import ChampionshipPage from "../../app/pages/championship/ChampionshipPage";
import StagePage from "../../app/pages/stages/StagePage";
import PlacesPage from "../../app/pages/places/PlacesPage";
import PlacePage from "../../app/pages/places/PlacePage";
import UserPage from "../../app/pages/users/UserPage";
export function NavigationRoutes() { export function NavigationRoutes() {
const {auth} = useAuth(); const {auth} = useAuth();
@@ -51,9 +53,10 @@ function ElementProvider({isPrivate, children}) {
const authPages = [ const authPages = [
{ {
children: (<HomeRedirect auth={true}/>),
isPrivate: false,
path: paths.home, path: paths.home,
isPrivate: true,
children: (<MenuPage/>),
exact: true,
}, },
{ {
path: paths.auth.signIn, path: paths.auth.signIn,
@@ -61,37 +64,44 @@ const authPages = [
isPrivate: false, isPrivate: false,
}, },
{ {
path: paths.bar.calc, path: paths.chp.championships,
children: (<CalcPage/>),
isPrivate: true, isPrivate: true,
children: (<ChampionshipsPage/>),
}, },
{ {
path: paths.dashboard.overview, path: paths.chp.championship,
isPrivate: true, isPrivate: true,
children: (<MenuPage/>), children: (<ChampionshipPage/>),
exact: true,
}, },
{ {
path: paths.bar.list, path: paths.calendar,
isPrivate: true, isPrivate: true,
children: (<BarChangePage/>), children: (<CalendarPage/>)
}, },
{ {
path: paths.bar.ingredients, path: paths.stg.stages,
isPrivate: true, isPrivate: true,
children: (<IngredientsPage/>) children: (<StagesPage/>)
}, },
{ {
path: paths.bar.ingredientEdit, path: paths.stg.stage,
isPrivate: true, isPrivate: true,
forAdmin: true, children: (<StagePage/>)
children: (<EditIngredientPage/>)
}, },
{ {
path: paths.bar.cocktailEdit, path: paths.places.places,
isPrivate: true, isPrivate: true,
forAdmin: true, children: (<PlacesPage/>)
children: (<EditCocktailPage/>) },
{
path: paths.places.place,
isPrivate: true,
children: (<PlacePage/>)
},
{
path: paths.users.user,
isPrivate: true,
children: (<UserPage/>)
}, },
{ {
path: paths.notFound, path: paths.notFound,
@@ -102,16 +112,11 @@ const authPages = [
const guestPages = [ const guestPages = [
{ {
path: paths.dashboard.overview, path: paths.home,
isPrivate: true, isPrivate: true,
children: (<MenuPage/>), children: (<MenuPage/>),
exact: true, exact: true,
}, },
{
children: (<HomeRedirect auth={true}/>),
isPrivate: false,
path: paths.home,
},
{ {
path: paths.auth.tg, path: paths.auth.tg,
isPrivate: false, isPrivate: false,

View File

@@ -1,37 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import {NavigationMenu} from "./NavigationMenu";
export function SideNav() {
return (
<Box
sx={{
'--SideNav-background': 'var(--mui-palette-neutral-950)',
'--SideNav-color': 'var(--mui-palette-common-white)',
'--NavItem-color': 'var(--mui-palette-neutral-300)',
'--NavItem-hover-background': 'rgba(255, 255, 255, 0.04)',
'--NavItem-active-background': 'var(--mui-palette-primary-main)',
'--NavItem-active-color': 'var(--mui-palette-primary-contrastText)',
'--NavItem-disabled-color': 'var(--mui-palette-neutral-500)',
'--NavItem-icon-color': 'var(--mui-palette-neutral-400)',
'--NavItem-icon-active-color': 'var(--mui-palette-primary-contrastText)',
'--NavItem-icon-disabled-color': 'var(--mui-palette-neutral-600)',
bgcolor: 'var(--SideNav-background)',
color: 'var(--SideNav-color)',
display: {xs: 'none', xl: 'flex'},
flexDirection: 'column',
height: '100%',
left: 0,
maxWidth: '100%',
position: 'fixed',
scrollbarWidth: 'none',
top: 0,
width: 'var(--SideNav-width)',
zIndex: 'var(--SideNav-zIndex)',
'&::-webkit-scrollbar': {display: 'none'},
}}
>
<NavigationMenu/>
</Box>
);
}

View File

@@ -0,0 +1,72 @@
import {Box, Chip, Paper, Typography} from "@mui/material";
import {STAGE_STATUSES} from "../../data/constants";
import React from "react";
const StagesHeader = ({stage}) => {
return(
<Paper sx={{p: 4, mb: 4}} variant="outlined">
<Typography variant="h4" gutterBottom>{stage.title}</Typography>
<Typography variant="h6" color="text.secondary" gutterBottom>
{stage.stage.name}
</Typography>
<Box sx={{display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 3, mt: 2}}>
<Box>
<Typography variant="subtitle2" color="text.secondary">Дата</Typography>
<Typography>
{new Date(stage.date).toLocaleDateString('ru-RU', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</Typography>
</Box>
<Box>
<Typography variant="subtitle2" color="text.secondary">Место</Typography>
<Typography>{stage.location}</Typography>
</Box>
<Box>
<Typography variant="subtitle2" color="text.secondary">Класс</Typography>
<Typography>{stage.class}</Typography>
</Box>
<Box>
<Typography variant="subtitle2" color="text.secondary">Статус</Typography>
<Chip
label={stage.status}
color={
stage.status === STAGE_STATUSES.GOING
? 'warning'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info'
: 'default'
}
sx={{
backgroundColor:
stage.status === STAGE_STATUSES.GOING
? 'warning.dark'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success.dark'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info.dark'
: 'grey.300',
color: 'white',
fontWeight: 500,
fontSize: '0.8rem'
}}
/>
</Box>
</Box>
{stage.description && (
<Typography variant="body1" paragraph sx={{mt: 3}}>
{stage.description}
</Typography>
)}
</Paper>
)
}
export default StagesHeader;

View File

@@ -27,6 +27,12 @@ export function UserProvider({children}) {
return; return;
} }
if (Object.keys(state.user).length === 0) { if (Object.keys(state.user).length === 0) {
const userMock = {
name: 'Sergey',
lastName: 'Kayashov'
}
setState((prev) => ({...prev, error: "", isLoading: false, user: userMock}))
return;
const {data, errorData} = await userClient.getMe(); const {data, errorData} = await userClient.getMe();
if (errorData) { if (errorData) {
setState((prev) => ({...prev, error: errorData, isLoading: false, user: {}})); setState((prev) => ({...prev, error: errorData, isLoading: false, user: {}}));

224
front/src/data/constants.js Normal file
View File

@@ -0,0 +1,224 @@
// src/data/constants.js
import {Trophy} from "@phosphor-icons/react";
import * as React from "react";
/**
* Константы для приложения «КартХолл»
*/
// export const FOOTER_MESSAGE = '© 2026 КартХолл. Все права защищены.';
export const FOOTER_MESSAGE = '2026 Race Invoice';
// export const WELCOME_MESSAGE_PRIME = "Добро пожаловать на платформу «КартХолл»!"
export const WELCOME_MESSAGE_PRIME = "Добро пожаловать на платформу «Race Invoice»!"
export const WELCOME_MESSAGE_SECOND = "Ваш гид по гоночным чемпионатам, этапам и онлайн‑соревнованиям."
export const RENT_QUEST = "Не гоняешь? Попробуй прокат!";
// export const RENT_MESSAGE = "Ощутите адреналин за рулём прокатного карта. Доступно ежедневно с 10:00 до 22:00."
export const RENT_MESSAGE = "Ощутите адреналин за рулём прокатного карта"
export const RENT_BUTTON = "Забронировать!"
// Классы участников
// Статусы этапов
export const STAGE_STATUSES = {
GOING: 'Идёт',
REGISTRATION_OPEN: 'Регистрация открыта',
PRE_REGISTRATION: 'Предрегистрация',
COMPLETED: 'Завершено'
};
// Моковые данные этапов соревнований
export const MOCK_STAGES = [
{
id: 1,
title: 'SWC Зимний чемпионат 20252026',
stage: {
name: '2й этап',
id: 1
},
date: '2026-02-08',
class: 'Юниоры',
status: STAGE_STATUSES.GOING,
description: 'Главный зимний турнир года. Призовой фонд — 500 000 ₽.',
location: 'Москва, стадион "Лужники"',
registrationLink: 'https://example.com/register/1',
stageId: 1,
icon: <Trophy fontSize="large"/>,
},
{
id: 2,
title: 'Honda Winter Cup',
stage: {
name: '1й этап',
id: 2
},
date: '2026-01-31',
class: 'Pro',
status: STAGE_STATUSES.REGISTRATION_OPEN,
description: 'Отборочный этап серии Honda. Участие — по заявке.',
location: 'Санкт-Петербург, трасса "Ижора"',
registrationLink: 'https://example.com/register/2'
},
{
id: 3,
title: 'Кубок Покровска (онлайн)',
stage: {
name: '1й этап',
id: 3
},
date: '2026-02-01',
class: 'Симулятор A',
status: STAGE_STATUSES.PRE_REGISTRATION,
description: 'Онлайн‑соревнование для пилотов симулятора.',
location: 'Онлайн-платформа',
registrationLink: 'https://example.com/register/3'
},
{
id: 4,
title: 'Гран-при Урала',
stage: 'Финальный этап',
date: '2026-03-15',
class: 'Взрослые',
status: STAGE_STATUSES.PRE_REGISTRATION,
description: 'Заключительный этап сезона. Борьба за чемпионский титул.',
location: 'Екатеринбург, автодром "Урал"',
registrationLink: 'https://example.com/register/4'
},
{
id: 5,
title: 'Открытый кубок Москвы',
stage: 'Квалификационный раунд',
date: '2026-01-20',
class: 'Amateur',
status: STAGE_STATUSES.COMPLETED,
description: 'Первый этап для начинающих пилотов.',
location: 'Москва, картодром "Сокольники"',
registrationLink: null
},
{
id: 6,
title: 'Этап 6',
stage: 'Тест',
date: '2026-04-01',
class: 'Pro',
status: STAGE_STATUSES.REGISTRATION_OPEN,
description: 'Тестовый этап для проверки системы.',
location: 'Казань, трасса "Казань‑Ринг"',
registrationLink: 'https://example.com/register/6'
},
{
id: 7,
title: 'Этап 7',
stage: 'Тест',
date: '2026-05-01',
class: 'Юниоры',
status: STAGE_STATUSES.GOING,
description: 'Пробный заезд для юниоров.',
location: 'Нижний Новгород, картодром "Нижегородский"',
registrationLink: null
},
{
id: 8,
title: 'Этап 8',
stage: 'Тест',
date: '2026-06-01',
class: 'Взрослые',
status: STAGE_STATUSES.PRE_REGISTRATION,
description: 'Экспериментальный формат гонки.',
location: 'Сочи, автодром "Сочи Автоспорт"',
registrationLink: 'https://example.com/register/8'
}
];
export const CHAMPIONSHIP_STAGES = [
{
id: 1,
title: 'SWS Зимний чемпионат 20252026',
stage: '2й этап',
date: '2026-02-08',
class: 'Юниоры',
status: 'Идёт',
season: 'Зима 20252026',
stages: 5,
classes: ['Юниоры', 'Взрослые', 'Богатыри', '35+'],
startDate: '18.01.2026',
endDate: '08.03.2026',
},
{
id: 2,
title: 'Honda Winter Cup 2026',
stage: '1й этап',
date: '2026-01-31',
class: 'Pro',
status: 'Регистрация открыта',
season: 'Зима 2026',
stages: 3,
classes: ['Pro', 'Amateur'],
startDate: '31.01.2026',
endDate: '28.02.2026',
},
{
id: 3,
title: 'Кубок Покровска 2026 (онлайн)',
stage: '1й этап',
date: '2026-02-01',
class: 'Симулятор A',
season: '2026',
stages: 4,
status: 'Предрегистрация',
classes: ['Симулятор A', 'Симулятор B'],
startDate: '01.02.2026',
endDate: '25.03.2026',
},
];
// Спонсоры (макеты URL)
export const sponsors = [
{name: 'Минеральная вода Ульянка', logo: '/assets/sponsors/ulyanka.svg'},
{name: 'Канистра', logo: '/assets/sponsors/kanistra.png'},
{name: 'NewDiffer', logo: '/assets/sponsors/newDiffer.svg'},
{name: 'WoodGrand', logo: '/assets/sponsors/woodGrand.svg'},
{name: 'Сервис Газ', logo: '/assets/sponsors/sgaz.png'},
{name: 'Саратов Союз Лифт Монтаж', logo: '/assets/sponsors/sslm.png'},
{name: 'Риострой', logo: '/assets/sponsors/riostroy.svg'},
];
// Дополнительные константы (если понадобятся позже)
export const DEFAULT_PAGINATION = {
page: 1,
limit: 5
};
export const SORT_ORDERS = {
ASC: 'asc',
DESC: 'desc'
};
// Пример данных площадок (в реальном проекте — из API)
export const places = [
{
id: 1,
name: 'Картодром KartHall',
images: [
'https://media73.ru/upload/iblock/542/5426aad66514849efe1febf0c36126bf.jpg',
'https://avatars.mds.yandex.net/i?id=1b63c0406714628f94080ff0a2bc0c58_l-5334917-images-thumbs&n=13'
],
address: 'г. Ульяновск, ул. Спортивная, д. 5',
type: 'Реальная трасса',
capacity: 20,
contact: '+7 (900) 123-45-67',
bookingNumber: 'Б-001',
},
{
id: 2,
name: 'Виртуальная трасса «Формула У»',
images: [
'/images/virtual-track.jpg'
],
type: 'Виртуальная площадка',
contact: 'support@formula-u.com',
bookingNumber: 'В-002',
},
// ... другие трассы
];

View File

@@ -5,6 +5,7 @@ import axios from "axios";
class TokenUtil { class TokenUtil {
checkToken(token) { checkToken(token) {
return true;
if (token == null || isExpired(token)) { if (token == null || isExpired(token)) {
return false; return false;
} }

View File

@@ -1,10 +1,9 @@
import {paths} from "./path"; import {paths} from "./path";
export const navItems = [ export const navItems = [
{key: 'menu', title: 'Меню', href: paths.dashboard.overview, icon: 'menu'}, {name: 'home', title: 'Домашняя страница', href: paths.home},
{key: 'barList', title: 'Список баров', href: paths.bar.list, icon: 'basket', forBarmen: true}, {name: 'championships', title: 'Чемпионаты', href: paths.chp.championships},
{key: 'ingredients', title: 'Список ингредиентов', href: paths.bar.ingredients, icon: 'basket', forBarmen: true}, {name: 'calendar', title: 'Календарь', href: paths.calendar},
{key: 'ingredientEdit', title: 'Ингредиенты', href: paths.bar.ingredientEdit, icon: 'ingredients', forAdmin: true}, {name: 'stages', title: 'Этапы', href: paths.stg.stages},
{key: 'cocktailEdit', title: 'Коктейли', href: paths.bar.cocktailEdit, icon: 'cocktail', forAdmin: true}, {name: 'places', title: 'Площадки', href: paths.places.places}
{key: 'calc', title: 'Калькулятор', href: paths.bar.calc, icon: 'calc', forAdmin: true},
]; ];

View File

@@ -1,25 +1,24 @@
export const paths = { export const paths = {
home: '/', home: '/',
chp:
{
championships: '/championships',
championship: '/championships/:id',
},
stg:
{
stages: '/stages',
stage: '/stages/:id',
},
places: {
places: '/places',
place: '/places/:id',
},
users: {
user: '/users/:id'
},
calendar: '/calendar',
auth: {signIn: '/auth/sign-in', bot: 'https://t.me/kayashovBarClientBot', tg: '/tg'}, auth: {signIn: '/auth/sign-in', bot: 'https://t.me/kayashovBarClientBot', tg: '/tg'},
dashboard: {
overview: '/menu'
},
visitor: {
inBar: "/visitors"
},
orders: {
my: '/orders'
},
bar: {
list: "/barList",
ordersQueue: '/queue',
ingredients: '/ingredients',
cocktails: "/cocktails",
ingredientEdit: '/ingredients/edit',
cocktailEdit: '/cocktail/edit',
menu: '/menuList',
calc: '/calc',
},
errors: {notFound: '/errors/not-found'}, errors: {notFound: '/errors/not-found'},
notFound: '*', notFound: '*',
}; };

View File

@@ -1,12 +1,13 @@
import {experimental_extendTheme as extendTheme} from '@mui/material/styles'; import {experimental_extendTheme as extendTheme} from '@mui/material/styles';
import {components} from "./components/components"; import {components} from "./components/components";
import shadows from "@mui/material/styles/shadows"; // import shadows from "@mui/material/styles/shadows";
import {typography} from "./typography"; import {typography} from "./typography";
import {colorSchemes} from "./color-schemes"; import {colorSchemes} from "./color-schemes";
import {shadows} from "./shadows";
export function createTTheme() { export function createTTheme() {
return extendTheme({ return extendTheme({
breakpoints: {values: {xs: 0, sm: 450, md: 600, lg: 900, xl: 1440}}, breakpoints: {values: {xs: 0, sm: 550, md: 900, lg: 1200, xl: 1500}},
colorSchemes: colorSchemes, colorSchemes: colorSchemes,
components: components, components: components,
shadows: shadows, shadows: shadows,