From 8e3f15d96851599c24bd29582aa4ad35348dd305 Mon Sep 17 00:00:00 2001 From: timothyman1 Date: Sun, 25 Feb 2024 20:14:45 +0300 Subject: [PATCH 01/11] chore: FSD implementation start --- src/App.css | 2 +- src/App.test.tsx | 2 +- src/Lists/ListItem.tsx | 6 +- src/Modal/Modal.css | 213 -------------------- src/Modal/ModalCreateItem.tsx | 7 +- src/Modal/ModalEditItem.tsx | 12 +- src/Modal/ModalRemoveItem.tsx | 5 +- src/app/hooks.ts | 2 +- src/app/{ => store}/store.ts | 4 +- src/{ => assets}/icons/close.svg | 0 src/{ => assets}/icons/down.svg | 0 src/{ => assets}/icons/edit.svg | 0 src/{ => assets}/icons/folder.svg | 0 src/{ => assets}/icons/important.svg | 0 src/{ => assets}/icons/remove.svg | 0 src/features/categoriesSlice.ts | 2 +- src/features/tasksSlice.ts | 2 +- src/index.tsx | 2 +- src/shared/ui/Modal/Modal.css | 32 +++ src/{ => shared/ui}/Modal/Modal.tsx | 0 src/{ => shared/ui}/Modal/ModalBtn.css | 0 src/{ => shared/ui}/Modal/ModalBtn.tsx | 2 + src/shared/ui/Modal/ModalDropdown.css | 70 +++++++ src/{ => shared/ui}/Modal/ModalDropdown.tsx | 15 +- src/shared/ui/Modal/ModalFooter.css | 4 + src/{ => shared/ui}/Modal/ModalFooter.tsx | 8 +- src/shared/ui/Modal/ModalHeader.css | 22 ++ src/{ => shared/ui}/Modal/ModalHeader.tsx | 12 +- src/shared/ui/Modal/ModalInput.css | 39 ++++ src/{ => shared/ui}/Modal/ModalInput.tsx | 12 +- src/shared/ui/Modal/ModalRow.css | 4 + src/{ => shared/ui}/Modal/ModalRow.tsx | 7 +- src/shared/ui/Modal/ModalText.css | 10 + src/{ => shared/ui}/Modal/ModalText.tsx | 4 + src/shared/ui/Modal/ModalTextarea.css | 27 +++ src/{ => shared/ui}/Modal/ModalTextarea.tsx | 6 +- src/shared/ui/Modal/index.ts | 12 ++ 37 files changed, 283 insertions(+), 262 deletions(-) delete mode 100644 src/Modal/Modal.css rename src/app/{ => store}/store.ts (77%) rename src/{ => assets}/icons/close.svg (100%) rename src/{ => assets}/icons/down.svg (100%) rename src/{ => assets}/icons/edit.svg (100%) rename src/{ => assets}/icons/folder.svg (100%) rename src/{ => assets}/icons/important.svg (100%) rename src/{ => assets}/icons/remove.svg (100%) create mode 100644 src/shared/ui/Modal/Modal.css rename src/{ => shared/ui}/Modal/Modal.tsx (100%) rename src/{ => shared/ui}/Modal/ModalBtn.css (100%) rename src/{ => shared/ui}/Modal/ModalBtn.tsx (94%) create mode 100644 src/shared/ui/Modal/ModalDropdown.css rename src/{ => shared/ui}/Modal/ModalDropdown.tsx (72%) create mode 100644 src/shared/ui/Modal/ModalFooter.css rename src/{ => shared/ui}/Modal/ModalFooter.tsx (82%) create mode 100644 src/shared/ui/Modal/ModalHeader.css rename src/{ => shared/ui}/Modal/ModalHeader.tsx (65%) create mode 100644 src/shared/ui/Modal/ModalInput.css rename src/{ => shared/ui}/Modal/ModalInput.tsx (68%) create mode 100644 src/shared/ui/Modal/ModalRow.css rename src/{ => shared/ui}/Modal/ModalRow.tsx (77%) create mode 100644 src/shared/ui/Modal/ModalText.css rename src/{ => shared/ui}/Modal/ModalText.tsx (76%) create mode 100644 src/shared/ui/Modal/ModalTextarea.css rename src/{ => shared/ui}/Modal/ModalTextarea.tsx (85%) create mode 100644 src/shared/ui/Modal/index.ts diff --git a/src/App.css b/src/App.css index 0304cec..29ea117 100644 --- a/src/App.css +++ b/src/App.css @@ -44,7 +44,7 @@ html { } .list-item-col1-row1__category::before { - content: url("./icons/folder.svg"); + content: url("assets/icons/folder.svg"); margin-right: 4px; position: relative; top: 3px; diff --git a/src/App.test.tsx b/src/App.test.tsx index 659cc13..2852fb4 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { Provider } from 'react-redux'; -import { store } from './app/store'; +import { store } from './app/store/store'; import App from './App'; test('renders learn react link', () => { diff --git a/src/Lists/ListItem.tsx b/src/Lists/ListItem.tsx index d2cc84e..6d8db0f 100644 --- a/src/Lists/ListItem.tsx +++ b/src/Lists/ListItem.tsx @@ -1,10 +1,10 @@ /* VENDOR */ -import { useState } from "react"; +import React, { useState } from "react"; import { useSelector } from "react-redux"; /* APPLICATION */ -import edit from "../icons/edit.svg"; -import remove from "../icons/remove.svg"; +import edit from "../assets/icons/edit.svg"; +import remove from "../assets/icons/remove.svg"; import { selectAllCategories } from "../features/categoriesSlice"; import { ModalEditItem } from "../Modal/ModalEditItem"; import { ModalRemoveItem } from "../Modal/ModalRemoveItem"; diff --git a/src/Modal/Modal.css b/src/Modal/Modal.css deleted file mode 100644 index 3595bd9..0000000 --- a/src/Modal/Modal.css +++ /dev/null @@ -1,213 +0,0 @@ -.modal { - height: 100vh; - width: 100vw; - background-color: rgba(0, 0, 0, 0.4); - position: fixed; - top: 0; - left: 0; - display: flex; - align-items: center; - justify-content: center; - opacity: 0; - pointer-events: none; - z-index: 1; -} - -.modal.active { - opacity: 1; - pointer-events: all; -} - -.modal__content { - box-sizing: border-box; - width: 800px; - padding: 24px; - background: #dbe2ef; - box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.5); - border-radius: 4px; -} - -.modal__content.small { - width: 600px; -} - -.modal__content-header { - display: flex; - justify-content: space-between; -} - -.modal__content-title { - font-style: normal; - font-weight: 500; - font-size: 40px; - line-height: 56px; - color: #3f72af; - margin-bottom: 32px; -} - -.modal__content-header__btn { - cursor: pointer; - box-sizing: border-box; - width: 25px; - height: 25px; - border: none; - background: transparent; -} - -.modal__content-text { - margin-bottom: 24px; - font-style: normal; - font-weight: 400; - font-size: 20px; - line-height: 24px; - color: #000000; -} - -.modal__content-footer { - display: flex; - justify-content: flex-end; -} - -.modal__content_row { - display: flex; - justify-content: space-between; -} - -.modalinput { - box-sizing: border-box; - padding: 8px; - height: 46px; - width: 100%; - background: transparent; - border: 2px solid #3f72af; - border-radius: 4px; - font-style: normal; - font-weight: 400; - font-size: 20px; - line-height: 46px; -} - -.modalinput::placeholder { - color: rgba(0, 0, 0, 0.5); -} - -.modalinput-wrapper { - box-sizing: border-box; - width: 364px; - position: relative; - margin-bottom: 34px; -} - -.modalinput-wrapper.large { - width: 100%; -} - -.modalinput:focus { - outline: none; -} - -[for="modalinput"], -[for="modaltextarea"], -.dropdown-label { - font-style: normal; - display: inline-block; - background-color: #dbe2ef; - font-weight: 400; - padding: 4px; - font-size: 18px; - line-height: 20px; - color: #3f72af; - position: absolute; - left: 12px; - top: -15px; -} - -.modalinput-icon { - position: absolute; - left: 55px; - top: -11px; - z-index: 1; -} - -.modaltextarea-wrapper { - position: relative; -} - -.modaltextarea { - resize: none; - box-sizing: border-box; - width: 100%; - height: 72px; - margin-bottom: 24px; - background: transparent; - border: 2px solid #3f72af; - border-radius: 4px; - font-style: normal; - font-weight: 400; - font-size: 20px; - line-height: 26px; - padding: 8px; -} - -.modaltextarea::placeholder { - color: rgba(0, 0, 0, 0.5); -} - -.modaltextarea:focus { - outline: none; -} - -.dropdown { - cursor: pointer; - box-sizing: border-box; - width: 364px; - height: 24px; - position: relative; - z-index: 1; -} - -.dropdown .dropdown-btn { - box-sizing: border-box; - padding: 8px; - display: flex; - align-items: center; /* для треугольника */ - justify-content: space-between; - background: #dbe2ef; - border: 2px solid #3f72af; - border-radius: 4px; - font-style: normal; - font-weight: 400; - font-size: 20px; - height: 46px; - color: #000; -} - -.dropdown .dropdown-btn.placeholder { - color: rgba(0, 0, 0, 0.5); -} - -.dropdown .dropdown-content { - box-sizing: border-box; - position: absolute; - top: 45px; - background: #dbe2ef; - border: 2px solid #3f72af; - border-radius: 4px; - width: 364px; -} - -.dropdown .dropdown-content .dropdown-item { - position: relative; - left: -2px; - box-sizing: border-box; - padding: 10px; - width: 364px; - border: none; - border-radius: 4px; - color: #3f72af; -} - -.dropdown .dropdown-content .dropdown-item:hover { - background-color: #3f72ff; - color: #fff; -} diff --git a/src/Modal/ModalCreateItem.tsx b/src/Modal/ModalCreateItem.tsx index d58b075..9e923c3 100644 --- a/src/Modal/ModalCreateItem.tsx +++ b/src/Modal/ModalCreateItem.tsx @@ -4,12 +4,7 @@ import { useDispatch } from "react-redux"; import { useLocation } from "react-router-dom"; /* APPLICATION */ -import { Modal } from "./Modal"; -import { ModalHeader } from "./ModalHeader"; -import { ModalInput } from "./ModalInput"; -import { ModalRow } from "./ModalRow"; -import { ModalTextarea } from "./ModalTextarea"; -import { ModalFooter } from "./ModalFooter"; +import { Modal, ModalHeader, ModalInput, ModalRow, ModalTextarea, ModalFooter } from "../shared/ui/Modal"; import { tasksAdded } from "../features/tasksSlice"; import { categoriesAdded } from "../features/categoriesSlice"; diff --git a/src/Modal/ModalEditItem.tsx b/src/Modal/ModalEditItem.tsx index f6fde0c..02a1d1a 100644 --- a/src/Modal/ModalEditItem.tsx +++ b/src/Modal/ModalEditItem.tsx @@ -4,12 +4,12 @@ import { useDispatch } from "react-redux"; import { useLocation } from "react-router-dom"; /* APPLICATION */ -import { Modal } from "./Modal"; -import { ModalHeader } from "./ModalHeader"; -import { ModalRow } from "./ModalRow"; -import { ModalInput } from "./ModalInput"; -import { ModalTextarea } from "./ModalTextarea"; -import { ModalFooter } from "./ModalFooter"; +import { Modal } from "../shared/ui/Modal/Modal"; +import { ModalHeader } from "../shared/ui/Modal/ModalHeader"; +import { ModalRow } from "../shared/ui/Modal/ModalRow"; +import { ModalInput } from "../shared/ui/Modal/ModalInput"; +import { ModalTextarea } from "../shared/ui/Modal/ModalTextarea"; +import { ModalFooter } from "../shared/ui/Modal/ModalFooter"; import { tasksUpdated } from "../features/tasksSlice"; import { categoriesUpdated } from "../features/categoriesSlice"; diff --git a/src/Modal/ModalRemoveItem.tsx b/src/Modal/ModalRemoveItem.tsx index 58b47f6..2e961be 100644 --- a/src/Modal/ModalRemoveItem.tsx +++ b/src/Modal/ModalRemoveItem.tsx @@ -3,10 +3,7 @@ import { useDispatch } from "react-redux"; import { useLocation } from "react-router-dom"; /* APPLICATION */ -import { Modal } from "./Modal"; -import { ModalHeader } from "./ModalHeader"; -import { ModalText } from "./ModalText"; -import { ModalFooter } from "./ModalFooter"; +import { Modal, ModalHeader, ModalText, ModalFooter } from "../shared/ui/Modal"; import { tasksRemoved, tasksClearedCategories } from "../features/tasksSlice"; import { categoriesRemoved } from "../features/categoriesSlice"; diff --git a/src/app/hooks.ts b/src/app/hooks.ts index 520e84e..565ec4d 100644 --- a/src/app/hooks.ts +++ b/src/app/hooks.ts @@ -1,5 +1,5 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; -import type { RootState, AppDispatch } from './store'; +import type { RootState, AppDispatch } from './store/store'; // Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch = () => useDispatch(); diff --git a/src/app/store.ts b/src/app/store/store.ts similarity index 77% rename from src/app/store.ts rename to src/app/store/store.ts index 1bed9d7..21a523e 100644 --- a/src/app/store.ts +++ b/src/app/store/store.ts @@ -1,6 +1,6 @@ import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit"; -import categoriesReducer from "../features/categoriesSlice"; -import tasksReducer from "../features/tasksSlice"; +import categoriesReducer from "../../features/categoriesSlice"; +import tasksReducer from "../../features/tasksSlice"; export const store = configureStore({ reducer: { diff --git a/src/icons/close.svg b/src/assets/icons/close.svg similarity index 100% rename from src/icons/close.svg rename to src/assets/icons/close.svg diff --git a/src/icons/down.svg b/src/assets/icons/down.svg similarity index 100% rename from src/icons/down.svg rename to src/assets/icons/down.svg diff --git a/src/icons/edit.svg b/src/assets/icons/edit.svg similarity index 100% rename from src/icons/edit.svg rename to src/assets/icons/edit.svg diff --git a/src/icons/folder.svg b/src/assets/icons/folder.svg similarity index 100% rename from src/icons/folder.svg rename to src/assets/icons/folder.svg diff --git a/src/icons/important.svg b/src/assets/icons/important.svg similarity index 100% rename from src/icons/important.svg rename to src/assets/icons/important.svg diff --git a/src/icons/remove.svg b/src/assets/icons/remove.svg similarity index 100% rename from src/icons/remove.svg rename to src/assets/icons/remove.svg diff --git a/src/features/categoriesSlice.ts b/src/features/categoriesSlice.ts index e4876f7..b5d1b92 100644 --- a/src/features/categoriesSlice.ts +++ b/src/features/categoriesSlice.ts @@ -3,7 +3,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { v4 as uuidv4 } from "uuid"; /* APPLICATION */ -import { RootState } from "../app/store"; +import { RootState } from "../app/store/store"; export interface CategoriesState { id: string; diff --git a/src/features/tasksSlice.ts b/src/features/tasksSlice.ts index 4ba7f07..531f481 100644 --- a/src/features/tasksSlice.ts +++ b/src/features/tasksSlice.ts @@ -3,7 +3,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { v4 as uuidv4 } from "uuid"; /* APPLICATION */ -import { RootState } from "../app/store"; +import { RootState } from "../app/store/store"; export interface CategoriesState { id: string; diff --git a/src/index.tsx b/src/index.tsx index ba2f6f0..bbba5ac 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,7 +5,7 @@ import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; /* APPLICATION */ -import { store } from "./app/store"; +import { store } from "./app/store/store"; import App from "./App"; //import reportWebVitals from './reportWebVitals'; import "./index.css"; diff --git a/src/shared/ui/Modal/Modal.css b/src/shared/ui/Modal/Modal.css new file mode 100644 index 0000000..3008331 --- /dev/null +++ b/src/shared/ui/Modal/Modal.css @@ -0,0 +1,32 @@ +.modal { + height: 100vh; + width: 100vw; + background-color: rgba(0, 0, 0, 0.4); + position: fixed; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + pointer-events: none; + z-index: 1; +} + +.modal.active { + opacity: 1; + pointer-events: all; +} + +.modal__content { + box-sizing: border-box; + width: 800px; + padding: 24px; + background: #dbe2ef; + box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.5); + border-radius: 4px; +} + +.modal__content.small { + width: 600px; +} \ No newline at end of file diff --git a/src/Modal/Modal.tsx b/src/shared/ui/Modal/Modal.tsx similarity index 100% rename from src/Modal/Modal.tsx rename to src/shared/ui/Modal/Modal.tsx diff --git a/src/Modal/ModalBtn.css b/src/shared/ui/Modal/ModalBtn.css similarity index 100% rename from src/Modal/ModalBtn.css rename to src/shared/ui/Modal/ModalBtn.css diff --git a/src/Modal/ModalBtn.tsx b/src/shared/ui/Modal/ModalBtn.tsx similarity index 94% rename from src/Modal/ModalBtn.tsx rename to src/shared/ui/Modal/ModalBtn.tsx index f9bbdcf..9f32f8b 100644 --- a/src/Modal/ModalBtn.tsx +++ b/src/shared/ui/Modal/ModalBtn.tsx @@ -1,3 +1,5 @@ +import React from "react"; + import "./ModalBtn.css"; interface ModalBtnProps { diff --git a/src/shared/ui/Modal/ModalDropdown.css b/src/shared/ui/Modal/ModalDropdown.css new file mode 100644 index 0000000..e5aa2b2 --- /dev/null +++ b/src/shared/ui/Modal/ModalDropdown.css @@ -0,0 +1,70 @@ +.dropdown { + cursor: pointer; + box-sizing: border-box; + width: 364px; + height: 24px; + position: relative; + z-index: 1; +} + +.dropdown-btn { + box-sizing: border-box; + padding: 8px; + display: flex; + align-items: center; /* для треугольника */ + justify-content: space-between; + background: #dbe2ef; + border: 2px solid #3f72af; + border-radius: 4px; + font-style: normal; + font-weight: 400; + font-size: 20px; + height: 46px; + color: #000; +} + +.placeholder { + color: rgba(0, 0, 0, 0.5); +} + +.content { + box-sizing: border-box; + position: absolute; + top: 45px; + background: #dbe2ef; + border: 2px solid #3f72af; + border-radius: 4px; + width: 364px; +} + +.item { + position: relative; + left: -2px; + box-sizing: border-box; + padding: 10px; + width: 364px; + border: none; + border-radius: 4px; + color: #3f72af; +} + +.item:hover { + background-color: #3f72ff; + color: #fff; +} + +[for="modalinput"], +[for="modaltextarea"], +.label { + font-style: normal; + display: inline-block; + background-color: #dbe2ef; + font-weight: 400; + padding: 4px; + font-size: 18px; + line-height: 20px; + color: #3f72af; + position: absolute; + left: 12px; + top: -15px; +} \ No newline at end of file diff --git a/src/Modal/ModalDropdown.tsx b/src/shared/ui/Modal/ModalDropdown.tsx similarity index 72% rename from src/Modal/ModalDropdown.tsx rename to src/shared/ui/Modal/ModalDropdown.tsx index 822028e..298f062 100644 --- a/src/Modal/ModalDropdown.tsx +++ b/src/shared/ui/Modal/ModalDropdown.tsx @@ -1,10 +1,11 @@ /* VENDOR */ -import { useState } from "react"; +import React, { useState } from "react"; import { useSelector } from "react-redux"; /* APPLICATION */ -import down from "../icons/down.svg"; -import { selectAllCategories } from "../features/categoriesSlice"; +import down from "../../../assets/icons/down.svg"; +import { selectAllCategories } from "../../../features/categoriesSlice"; +import "./ModalDropdown.css" interface ModalDropdownProps { selected: string | undefined; @@ -20,17 +21,17 @@ export const ModalDropdown: React.FC = ({ return (
setIsActive(!isActive)}> - Категория -
+ Категория +
{options.find((option) => option.id === selected)?.name || "Выберите категорию"} open dropdown
{isActive && ( -
+
{options.map((option) => (
{ setSelected(option.id); setIsActive(false); diff --git a/src/shared/ui/Modal/ModalFooter.css b/src/shared/ui/Modal/ModalFooter.css new file mode 100644 index 0000000..9584e61 --- /dev/null +++ b/src/shared/ui/Modal/ModalFooter.css @@ -0,0 +1,4 @@ +.footer { + display: flex; + justify-content: flex-end; +} \ No newline at end of file diff --git a/src/Modal/ModalFooter.tsx b/src/shared/ui/Modal/ModalFooter.tsx similarity index 82% rename from src/Modal/ModalFooter.tsx rename to src/shared/ui/Modal/ModalFooter.tsx index 3a6669c..60ded64 100644 --- a/src/Modal/ModalFooter.tsx +++ b/src/shared/ui/Modal/ModalFooter.tsx @@ -1,4 +1,8 @@ -import { ModalBtn } from "./ModalBtn"; +import React from "react"; + +/* APPLICATION */ +import { ModalBtn } from "./"; +import './ModalFooter.css' interface ModalFooterProps { clearState?(): void; @@ -16,7 +20,7 @@ export const ModalFooter: React.FC = ({ onSubmit, }) => { return ( -