diff --git a/client/src/components/Memberships/EditStep/EditStep.jsx b/client/src/components/Memberships/EditStep/EditStep.jsx new file mode 100755 index 0000000..5c8cd59 --- /dev/null +++ b/client/src/components/Memberships/EditStep/EditStep.jsx @@ -0,0 +1,164 @@ +import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import { Input, Popup } from '../../../lib/custom-ui'; + +import { useField, useSteps } from '../../../hooks'; +import UserItem from './UserItem'; +import DeleteStep from '../../DeleteStep'; + +import styles from './EditStep.module.scss'; + +const StepTypes = { + EDIT_PERMISSIONS: 'EDIT_PERMISSIONS', + DELETE: 'DELETE', +}; + +const EditStep = React.memo( + ({ users, currentUserIds, permissionsSelectStep, title, onUpdate, onDelete, onClose }) => { + const [t] = useTranslation(); + const [step, openStep, handleBack] = useSteps(); + const [search, handleSearchChange] = useField(''); + const cleanSearch = useMemo(() => search.trim().toLowerCase(), [search]); + + const filteredUsers = useMemo( + () => + users.filter( + (user) => + user.email.includes(cleanSearch) || + user.name.toLowerCase().includes(cleanSearch) || + (user.username && user.username.includes(cleanSearch)), + ), + [users, cleanSearch], + ); + + const searchField = useRef(null); + + const handleEditPermissionsClick = useCallback(() => { + openStep(StepTypes.EDIT_PERMISSIONS); + }, [openStep]); + + const handleDeleteClick = useCallback(() => { + openStep(StepTypes.DELETE); + }, [openStep]); + + const handleUserSelect = useCallback( + (id) => { + openStep(StepTypes.EDIT_PERMISSIONS, { + userId: id, + }); + }, + [openStep], + ); + + const handleRoleSelect = useCallback( + (data) => { + onUpdate({ + userId: step.params.userId, + ...data, + }); + }, + [onUpdate, step], + ); + + useEffect(() => { + searchField.current.focus({ + preventScroll: true, + }); + }, []); + + if (step) { + switch (step.type) { + case StepTypes.EDIT_PERMISSIONS: { + const currentUser = users.find((user) => user.id === step.params.userId); + + if (currentUser) { + const PermissionsSelectStep = permissionsSelectStep; + + return ( + + ); + } + break; + } + case StepTypes.DELETE: + return ( + + ); + default: + } + } + + return ( + <> + + {t(title, { + context: 'title', + })} + + + + {filteredUsers.length > 0 && ( +
+ {filteredUsers.map((user) => ( + handleUserSelect(user.id)} + /> + ))} +
+ )} +
+ + ); + }, +); + +EditStep.propTypes = { + /* eslint-disable react/forbid-prop-types */ + users: PropTypes.array.isRequired, + currentUserIds: PropTypes.array.isRequired, + /* eslint-disable react/forbid-prop-types */ + permissionsSelectStep: PropTypes.elementType, + title: PropTypes.string, + onUpdate: PropTypes.func, + onDelete: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, +}; + +EditStep.defaultProps = { + permissionsSelectStep: undefined, + title: 'common.editMember', + onUpdate: undefined, +}; + +export default EditStep; diff --git a/client/src/components/Memberships/EditStep/EditStep.module.scss b/client/src/components/Memberships/EditStep/EditStep.module.scss new file mode 100644 index 0000000..95be8d0 --- /dev/null +++ b/client/src/components/Memberships/EditStep/EditStep.module.scss @@ -0,0 +1,21 @@ +:global(#app) { + .users { + margin-top: 8px; + max-height: 60vh; + overflow-x: hidden; + overflow-y: auto; + scrollbar-width: thin; + + &::-webkit-scrollbar { + width: 5px; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + border-radius: 3px; + } + } +} diff --git a/client/src/components/Memberships/EditStep/UserItem.jsx b/client/src/components/Memberships/EditStep/UserItem.jsx new file mode 100644 index 0000000..a61bb81 --- /dev/null +++ b/client/src/components/Memberships/EditStep/UserItem.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +import User from '../../User'; + +import styles from './UserItem.module.scss'; + +const UserItem = React.memo(({ name, avatarUrl, isActive, onSelect }) => ( + +)); + +UserItem.propTypes = { + name: PropTypes.string.isRequired, + avatarUrl: PropTypes.string, + isActive: PropTypes.bool.isRequired, + onSelect: PropTypes.func.isRequired, +}; + +UserItem.defaultProps = { + avatarUrl: undefined, +}; + +export default UserItem; diff --git a/client/src/components/Memberships/EditStep/UserItem.module.scss b/client/src/components/Memberships/EditStep/UserItem.module.scss new file mode 100644 index 0000000..f5c06b6 --- /dev/null +++ b/client/src/components/Memberships/EditStep/UserItem.module.scss @@ -0,0 +1,47 @@ +:global(#app) { + .menuItem { + background: transparent; + border: none; + border-radius: 0.28571429rem; + cursor: pointer; + display: block; + margin: 0; + outline: 0; + overflow: hidden; + padding: 4px; + text-align: left; + width: 100%; + + &:hover { + background: rgba(0, 0, 0, 0.05); + } + } + + .menuItemText { + display: inline-block; + line-height: 32px; + position: relative; + width: calc(100% - 40px); + } + + .menuItemTextActive:before { + bottom: 2px; + color: #798d99; + content: "Г"; + font-size: 18px; + font-weight: normal; + line-height: 36px; + position: absolute; + right: 2px; + text-align: center; + transform: rotate(-135deg); + width: 36px; + } + + .user { + display: inline-block; + line-height: 32px; + padding-right: 8px; + width: 40px; + } +} diff --git a/client/src/components/Memberships/EditStep/index.js b/client/src/components/Memberships/EditStep/index.js new file mode 100644 index 0000000..c17abb0 --- /dev/null +++ b/client/src/components/Memberships/EditStep/index.js @@ -0,0 +1,3 @@ +import EditStep from './EditStep'; + +export default EditStep; diff --git a/client/src/components/Memberships/Memberships.jsx b/client/src/components/Memberships/Memberships.jsx index 73adcd1..7249a4c 100644 --- a/client/src/components/Memberships/Memberships.jsx +++ b/client/src/components/Memberships/Memberships.jsx @@ -4,6 +4,7 @@ import { Button } from 'semantic-ui-react'; import { usePopup } from '../../lib/popup'; import AddStep from './AddStep'; +import EditStep from './EditStep'; import ActionsStep from './ActionsStep'; import User from '../User'; @@ -15,6 +16,7 @@ const Memberships = React.memo( allUsers, permissionsSelectStep, addTitle, + editTitle, leaveButtonContent, leaveConfirmationTitle, leaveConfirmationContent, @@ -31,6 +33,7 @@ const Memberships = React.memo( }) => { const AddPopup = usePopup(AddStep); const ActionsPopup = usePopup(ActionsStep); + const EditPopup = usePopup(EditStep); // Number of display slots available for showing user icons const userDisplaySlots = 5; @@ -69,7 +72,18 @@ const Memberships = React.memo( ))} {remainingUsers.length > 0 && ( - + {remainingUsers.length} other Members + item.user.id)} + permissionsSelectStep={permissionsSelectStep} + title={editTitle} + onUpdate={onUpdate} + onDelete={onDelete} + > + + + {remainingUsers.length} other Members + + )} {canEdit && ( { items={items} allUsers={allUsers} addTitle="common.addManager" + editTitle="common.editManager" leaveButtonContent="action.leaveProject" leaveConfirmationTitle="common.leaveProject" leaveConfirmationContent="common.areYouSureYouWantToLeaveProject" diff --git a/client/src/locales/en/core.js b/client/src/locales/en/core.js index 83b0116..6dd5921 100644 --- a/client/src/locales/en/core.js +++ b/client/src/locales/en/core.js @@ -80,6 +80,7 @@ export default { editEmail_title: 'Edit E-mail', editInformation_title: 'Edit Information', editLabel_title: 'Edit Label', + editMember_title: 'Edit Member', editPassword_title: 'Edit Password', editPermissions_title: 'Edit Permissions', editStopwatch_title: 'Edit Stopwatch', @@ -201,6 +202,7 @@ export default { editDescription_title: 'Edit Description', editEmail_title: 'Edit E-mail', editInformation_title: 'Edit Information', + editMember: 'Edit member', editPassword_title: 'Edit Password', editPermissions: 'Edit permissions', editStopwatch_title: 'Edit Stopwatch', diff --git a/docker-compose-db.yml b/docker-compose-db.yml index 9bc6bc5..e770947 100644 --- a/docker-compose-db.yml +++ b/docker-compose-db.yml @@ -7,7 +7,7 @@ services: volumes: - db-data:/var/lib/postgresql/data ports: - - 5432:5432 + - 5433:5432 environment: - POSTGRES_DB=planka - POSTGRES_HOST_AUTH_METHOD=trust diff --git a/package-lock.json b/package-lock.json index a13d186..dc5a259 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "dependencies": { "concurrently": "^8.2.2", "husky": "^8.0.3", - "lint-staged": "^15.1.0" + "lint-staged": "^15.1.0", + "sass": "^1.72.0" }, "devDependencies": { "eslint": "^8.53.0", @@ -275,6 +276,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -296,6 +309,17 @@ "node": ">=0.6" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", @@ -379,6 +403,40 @@ "node": ">=8" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -1047,6 +1105,19 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1158,6 +1229,11 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -1199,6 +1275,17 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", @@ -1218,7 +1305,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1238,7 +1324,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1551,6 +1636,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -1795,6 +1888,17 @@ } ] }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", @@ -2042,6 +2146,22 @@ "tslib": "^2.1.0" } }, + "node_modules/sass": { + "version": "1.72.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz", + "integrity": "sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2106,6 +2226,14 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spawn-command": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", @@ -2635,6 +2763,15 @@ "color-convert": "^2.0.1" } }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2653,6 +2790,11 @@ "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", "dev": true }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" + }, "bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", @@ -2714,6 +2856,31 @@ } } }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -3192,6 +3359,12 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -3261,6 +3434,11 @@ "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true }, + "immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3293,6 +3471,14 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", @@ -3302,8 +3488,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-fullwidth-code-point": { "version": "4.0.0", @@ -3314,7 +3499,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -3531,6 +3715,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, "npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -3682,6 +3871,14 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, "regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", @@ -3846,6 +4043,16 @@ "tslib": "^2.1.0" } }, + "sass": { + "version": "1.72.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz", + "integrity": "sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==", + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3885,6 +4092,11 @@ } } }, + "source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" + }, "spawn-command": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", diff --git a/package.json b/package.json index 68f3df1..59d29aa 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "dependencies": { "concurrently": "^8.2.2", "husky": "^8.0.3", - "lint-staged": "^15.1.0" + "lint-staged": "^15.1.0", + "sass": "^1.72.0" }, "devDependencies": { "eslint": "^8.53.0",