diff --git a/skypro-kanban/data.js b/skypro-kanban/data.js new file mode 100644 index 0000000..5abf4b3 --- /dev/null +++ b/skypro-kanban/data.js @@ -0,0 +1,79 @@ +export const cardList = [ + { + id: 1, + topic: "Web Design", + title: "Название задачи", + date: "30.10.23", + status: "БЕЗ СТАТУСА" + }, + { + id: 2, + topic: "Research", + title: "Название задачи", + date: "31.10.23", + status: "БЕЗ СТАТУСА" + }, + { + id: 3, + topic: "Web Design", + title: "Название задачи", + date: "30.10.23", + status: "БЕЗ СТАТУСА" + }, + { + id: 4, + topic: "Copywriting", + title: "Название задачи", + date: "31.10.23", + status: "БЕЗ СТАТУСА" + }, + { + id: 5, + topic: "Web Design", + title: "Название задачи", + date: "31.10.23", + status: "БЕЗ СТАТУСА" + }, + { + id: 6, + topic: "Research", + title: "Название задачи", + date: "30.10.23", + status: "НУЖНО СДЕЛАТЬ" + }, + { + id: 7, + topic: "Research", + title: "Название задачи", + date: "30.10.23", + status: "В РАБОТЕ" + }, + { + id: 8, + topic: "Copywriting", + title: "Название задачи", + date: "30.10.23", status: "В РАБОТЕ" + }, + { + id: 9, + topic: "Web Design", + title: "Название задачи", + date: "30.10.23", + status: "В РАБОТЕ" + }, + { + id: 10, + topic: "Research", + title: "Название задачи", + date: "01.11.23", + status: "ТЕСТИРОВАНИЕ" + }, + { + id: 11, + topic: "Research", + title: "Название задачи", + date: "01.11.23", + status: "ГОТОВО" + }, +]; + diff --git a/skypro-kanban/package-lock.json b/skypro-kanban/package-lock.json index eb01371..2b59ca3 100644 --- a/skypro-kanban/package-lock.json +++ b/skypro-kanban/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.25.1" + "react-router-dom": "^6.25.1", + "styled-components": "^6.1.12" }, "devDependencies": { "@types/react": "^18.3.3", @@ -393,6 +394,27 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -1302,6 +1324,12 @@ "@types/react": "*" } }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", + "license": "MIT" + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -1646,6 +1674,15 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001642", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", @@ -1728,11 +1765,30 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/data-view-buffer": { @@ -3431,7 +3487,6 @@ "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -3678,7 +3733,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true, "license": "ISC" }, "node_modules/possible-typed-array-names": { @@ -3720,6 +3774,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4094,6 +4154,12 @@ "node": ">= 0.4" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4140,7 +4206,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -4262,6 +4327,68 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-components": { + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.12.tgz", + "integrity": "sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.38", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4305,6 +4432,12 @@ "node": ">=4" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/skypro-kanban/package.json b/skypro-kanban/package.json index ae7570e..3da99a7 100644 --- a/skypro-kanban/package.json +++ b/skypro-kanban/package.json @@ -12,7 +12,8 @@ "dependencies": { "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.25.1" + "react-router-dom": "^6.25.1", + "styled-components": "^6.1.12" }, "devDependencies": { "@types/react": "^18.3.3", diff --git a/skypro-kanban/src/App.css b/skypro-kanban/src/App.css index c094f14..353706c 100644 --- a/skypro-kanban/src/App.css +++ b/skypro-kanban/src/App.css @@ -1125,4 +1125,13 @@ body { .pop-exit__form-group { display: block; } +} + +.loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + font-size: 24px; + color: #333; } \ No newline at end of file diff --git a/skypro-kanban/src/App.jsx b/skypro-kanban/src/App.jsx index d985f0f..6c32f36 100644 --- a/skypro-kanban/src/App.jsx +++ b/skypro-kanban/src/App.jsx @@ -1,20 +1,58 @@ -import React from 'react'; + +import React, { useState, useEffect } from 'react'; +import { ThemeProvider } from 'styled-components'; import Header from './components/Header/Header'; import Main from './components/Main/Main'; import PopBrowse from './components/Popups/PopBrowse/PopBrowse'; import PopNewCard from './components/Popups/PopNewCard/PopNewCard'; import PopUser from './components/Popups/PopUser/PopUser'; -import './App.css'; +import { cardList } from '../data'; +import GlobalStyle from './styles/GlobalStyles'; +import { themeColors } from './styles/Themes'; +import { LoadingWrapper, wrapperStyles } from "./styles/CommonStyles"; +import styled from 'styled-components'; + +const AppWrapper = styled.div` + ${wrapperStyles} +`; function App() { + const [cards, setCards] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [isUserPopupOpen, setIsUserPopupOpen] = useState(false); + + useEffect(() => { + setTimeout(() => { + setCards(cardList); + setIsLoading(false); + }, 2000); + }, []); + + function onCardAdd() { + const newCard = { + id: cards.length + 1, + topic: "Research", + title: "Название задачи", + date: new Date().toLocaleDateString('ru-RU'), + status: "Без статуса" + }; + setCards([...cards, newCard]); + } return ( -
- - - -
-
-
+ + + + + +
setIsUserPopupOpen(!isUserPopupOpen)} /> + + {isLoading ? ( + Данные загружаются... + ) : ( +
+ )} + + ); } diff --git a/skypro-kanban/src/components/Calendar/Calendar.jsx b/skypro-kanban/src/components/Calendar/Calendar.jsx index 6e82b3f..0b9e8f5 100644 --- a/skypro-kanban/src/components/Calendar/Calendar.jsx +++ b/skypro-kanban/src/components/Calendar/Calendar.jsx @@ -1,80 +1,66 @@ import React from 'react'; -import '../../App.css'; +import { + CalendarWrapper, + CalendarTitle, + CalendarContent, + CalendarMonth, + CalendarDaysNames, + CalendarDayName, + CalendarCells, + CalendarCell, + CalendarNav, + NavAction, + CalendarPeriod, + CalendarP, + CalendarBlock, + NavActions +} from './CalendarStyles'; function Calendar() { return ( -
-

Даты

-
-
-
Сентябрь 2023
-
-
+ + Даты + + + Сентябрь 2023 + + -
-
+ + -
-
-
-
-
-
пн
-
вт
-
ср
-
чт
-
пт
-
сб
-
вс
-
-
-
28
-
29
-
30
-
31
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
1
-
-
+ + + + + + пн + вт + ср + чт + пт + сб + вс + + + 28 + 1 + 8 + {/* ... остальные ячейки */} + + -
-

Выберите срок исполнения .

-
-
-
+ + + Выберите срок исполнения . + + + + ); } diff --git a/skypro-kanban/src/components/Calendar/CalendarStyles.js b/skypro-kanban/src/components/Calendar/CalendarStyles.js new file mode 100644 index 0000000..fc74f1d --- /dev/null +++ b/skypro-kanban/src/components/Calendar/CalendarStyles.js @@ -0,0 +1,139 @@ +import styled, { css } from 'styled-components'; +import { themeColors } from '../../styles/Themes'; + +export const NavActions = styled.div` + display: flex; + align-items: center; + justify-content: space-between; +`; + +export const CalendarWrapper = styled.div` + width: 182px; + margin-bottom: 20px; +`; + +export const CalendarTitle = styled.p` + margin-bottom: 14px; + padding: 0 7px; + color: ${props => props.theme.textPrimary}; + font-size: 14px; + font-weight: 600; + line-height: 1; +`; + +export const CalendarContent = styled.div` + margin-bottom: 12px; +`; + +export const CalendarMonth = styled.div` + color: ${themeColors.textSecondary}; + font-size: 14px; + line-height: 25px; + font-weight: 600; +`; + +export const CalendarDaysNames = styled.div` + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + margin: 7px 0; + padding: 0 7px; +`; + +export const CalendarDayName = styled.div` + color: ${themeColors.textSecondary}; + font-size: 10px; + font-weight: 500; + line-height: normal; + letter-spacing: -0.2px; +`; + +export const CalendarCells = styled.div` + width: 182px; + height: 126px; + display: flex; + flex-wrap: wrap; +`; + +export const CalendarCell = styled.div` + width: 22px; + height: 22px; + margin: 2px; + border-radius: 50%; + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: center; + color: ${themeColors.textSecondary}; + font-size: 10px; + line-height: 1; + letter-spacing: -0.2px; + cursor: pointer; + + ${props => props.$isOtherMonth && ` + opacity: 0; + `} + + ${props => props.$isCurrent && ` + font-weight: 700; + `} + + &._other-month { + opacity: 0; + } + + &._cell-day:hover { + color: ${themeColors.textSecondary}; + background-color: ${themeColors.background}; + } + + &._active-day { + background-color: ${themeColors.secondary}; + color: ${themeColors.cardBackground}; + } + + &._current { + font-weight: 700; + } +`; + +export const CalendarNav = styled.div` + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 14px; + padding: 0 7px; +`; + +export const NavAction = styled.div` + width: 18px; + height: 25px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + + svg { + fill: ${themeColors.textSecondary}; + } +`; + +export const CalendarPeriod = styled.div` + padding: 0 7px; +`; + +export const CalendarP = styled.p` + color: ${themeColors.textSecondary}; + font-size: 10px; + line-height: 1; + + span { + color: ${themeColors.textPrimary}; + } +`; + +export const CalendarBlock = styled.div` + display: block; +`; \ No newline at end of file diff --git a/skypro-kanban/src/components/Card/Card.jsx b/skypro-kanban/src/components/Card/Card.jsx index 27d3e09..cfaaecc 100644 --- a/skypro-kanban/src/components/Card/Card.jsx +++ b/skypro-kanban/src/components/Card/Card.jsx @@ -1,37 +1,44 @@ import React from 'react'; -import '../../App.css'; +import { + CardWrapper, + CardGroup, + CardTheme, + ThemeText, + CardButton, + ButtonDot, + CardContent, + CardTitle, + CardDate, + DateText +} from './CardStyles'; -function Card({ title, category, date }) { - const getThemeClass = (category) => { - switch (category.toLowerCase()) { - case 'web design': return '_orange'; - case 'research': return '_green'; - case 'copywriting': return '_purple'; - default: return ''; +function Card({ title, topic, date }) { + const getTopicClassName = (topic) => { + switch (topic.toLowerCase()) { + case 'web design': return 'web-design'; + case 'research': return 'research'; + case 'copywriting': return 'copywriting'; + default: return 'default'; } }; - const themeClass = getThemeClass(category); + const topicClassName = getTopicClassName(topic); return ( -
-
-
-

{category}

-
- -
-
- -
- -

{title}

-
-
+ + + + {topic} + + + + + + + + + {title} + @@ -43,10 +50,10 @@ function Card({ title, category, date }) { -

{date}

-
-
-
+ {date} + + + ); } diff --git a/skypro-kanban/src/components/Card/CardStyles.js b/skypro-kanban/src/components/Card/CardStyles.js new file mode 100644 index 0000000..70f76c2 --- /dev/null +++ b/skypro-kanban/src/components/Card/CardStyles.js @@ -0,0 +1,84 @@ +import styled from 'styled-components'; +import { cardContainerStyles } from '../../styles/CommonStyles'; + +export const CardWrapper = styled.div` + ${cardContainerStyles} + width: 220px; + height: 130px; + display: flex; + flex-direction: column; + padding: 15px 13px 19px; + margin-bottom: 15px; // Добавляем отступ снизу +`; + +export const CardGroup = styled.div` + width: 100%; + height: 20px; + margin-bottom: 12px; + display: flex; + align-items: center; + justify-content: space-between; +`; + +export const CardTheme = styled.div` + width: auto; + height: 20px; + padding: 5px 14px; + border-radius: 18px; + background-color: ${({ $topic, theme }) => + theme.topicStyles[$topic]?.backgroundColor || theme.topicStyles.default.backgroundColor}; +`; + +export const ThemeText = styled.p` + font-size: 10px; + font-weight: 600; + line-height: 10px; + color: ${({ $topic, theme }) => + theme.topicStyles[$topic]?.color || theme.topicStyles.default.color}; +`; + +export const CardButton = styled.div` + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: space-around; + padding: 2px; +`; + +export const ButtonDot = styled.div` + width: 4px; + height: 4px; + border-radius: 50%; + background-color: ${props => props.theme.textSecondary}; +`; + +export const CardContent = styled.div` + height: 64px; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; +`; + +export const CardTitle = styled.h3` + font-size: 14px; + font-weight: 500; + line-height: 18px; + color: ${props => props.theme.textPrimary}; + margin-bottom: 10px; +`; + +export const CardDate = styled.div` + display: flex; + align-items: center; + justify-content: flex-start; +`; + +export const DateText = styled.p` + margin-left: 6px; + font-size: 10px; + line-height: 13px; + color: ${props => props.theme.textSecondary}; + letter-spacing: 0.2px; +`; \ No newline at end of file diff --git a/skypro-kanban/src/components/Column/Column.jsx b/skypro-kanban/src/components/Column/Column.jsx index 8bc4205..bb4bdd8 100644 --- a/skypro-kanban/src/components/Column/Column.jsx +++ b/skypro-kanban/src/components/Column/Column.jsx @@ -1,53 +1,25 @@ -// import React from 'react'; -// import Card from '../Card/Card'; -// import '../../App.css'; - -// function Column({ title, tasks }) { -// return ( -//
-//
-//

{title}

-//
-//
-// {tasks.map(task => ( -//
-// -//
-// ))} -//
-//
-// ); -// } - -// export default Column; - import React from 'react'; import Card from '../Card/Card'; -import '../../App.css'; +import { ColumnWrapper, ColumnTitle, CardsContainer } from './ColumnStyles'; function Column({ title, tasks }) { return ( -
-
+ +

{title}

-
-
- {tasks.map((task, index) => ( -
- -
+ + + {tasks.map((task) => ( + ))} -
-
+ + ); } -export default Column; +export default Column; \ No newline at end of file diff --git a/skypro-kanban/src/components/Column/ColumnStyles.js b/skypro-kanban/src/components/Column/ColumnStyles.js new file mode 100644 index 0000000..a150a60 --- /dev/null +++ b/skypro-kanban/src/components/Column/ColumnStyles.js @@ -0,0 +1,32 @@ +import styled from 'styled-components'; + +export const ColumnWrapper = styled.div` + width: 20%; + margin: 0 auto; + display: block; +`; + +export const ColumnTitle = styled.div` + padding: 0 10px; + margin: 15px 0; + + p { + color: ${props => props.theme.textSecondary}; + font-size: 14px; + font-weight: 600; + line-height: 1; + text-transform: uppercase; + } +`; + +export const CardsContainer = styled.div` + width: 100%; + display: block; + position: relative; +`; +export const CardsItem = styled.div` + padding: 5px; + animation-name: card-animation; + animation-duration: 500ms; + animation-timing-function: linear; +`; \ No newline at end of file diff --git a/skypro-kanban/src/components/Header/Header.jsx b/skypro-kanban/src/components/Header/Header.jsx index 3741610..e940164 100644 --- a/skypro-kanban/src/components/Header/Header.jsx +++ b/skypro-kanban/src/components/Header/Header.jsx @@ -1,45 +1,72 @@ -import React from 'react'; -import '../../App.css'; +import React, { useState } from 'react'; +import { + HeaderWrapper, + HeaderBlock, + HeaderLogo, + HeaderNav, + HeaderBtnMainNew, + HeaderUser, + UserMenu, + UserName, + UserEmail, + ThemeToggleWrapper, + ThemeToggle, + ToggleInput, + ToggleSlider, + ExitButton, + LogoLink, + LogoImage +} from './HeaderStyles'; +import styled from 'styled-components'; +import { containerStyles } from "../../styles/CommonStyles"; + +const Container = styled.div` + ${containerStyles} +`; + +function Header({ onCardAdd, onThemeToggle }) { + const [isMenuOpen, setIsMenuOpen] = useState(false); -function Header() { const handleUserClick = (e) => { - e.preventDefault(); // Предотвращаем действие по умолчанию - const targetElement = document.querySelector(e.currentTarget.getAttribute('href')); - if (targetElement) { - targetElement.style.display = targetElement.style.display === 'block' ? 'none' : 'block'; - } + e.preventDefault(); + setIsMenuOpen(!isMenuOpen); }; return ( -
-
-
-
- logo -
-
- logo -
- -
-
-
+ + + + + + + + + + + + Создать новую задачу + + + Ivan Ivanov + + {isMenuOpen && ( + + Ivan Ivanov + ivan.ivanov@gmail.com + + Темная тема + + + + + + Выйти + + )} + + + + ); } diff --git a/skypro-kanban/src/components/Header/HeaderStyles.js b/skypro-kanban/src/components/Header/HeaderStyles.js new file mode 100644 index 0000000..fd19ea2 --- /dev/null +++ b/skypro-kanban/src/components/Header/HeaderStyles.js @@ -0,0 +1,195 @@ +import styled, { css } from 'styled-components'; +import { buttonStyles } from '../../styles/CommonStyles'; + +export const HeaderWrapper = styled.header` + width: 100%; + margin: 0 auto; + background-color: ${props => props.theme.cardBackground}; +`; + +export const HeaderBlock = styled.div` + height: 70px; + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + position: relative; + top: 0; + left: 0; + padding: 0 10px; +`; + +export const HeaderLogo = styled.div` + img { + width: 85px; + } +`; + +export const HeaderNav = styled.nav` + max-width: 290px; + padding: 0; + display: flex; + align-items: center; + justify-content: center; +`; + +export const HeaderBtnMainNew = styled.button` + ${buttonStyles} + width: auto; + min-width: 178px; + height: 30px; + padding: 0 20px; + margin-right: 20px; + font-size: 14px; + white-space: nowrap; + + @media (max-width: 1200px) { + font-size: 12px; + padding: 0 15px; + } + + @media (max-width: 992px) { + min-width: 150px; + margin-right: 10px; + } +`; + +export const HeaderUser = styled.a` + height: 20px; + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: center; + font-size: 14px; + line-height: 20px; + color: ${props => props.theme.primary}; + + &::after { + content: ""; + display: block; + width: 6px; + height: 6px; + border-radius: 1px; + border-left: 1.9px solid ${props => props.theme.primary}; + border-bottom: 1.9px solid ${props => props.theme.primary}; + transform: rotate(-45deg); + margin: -6px 0 0 5px; + padding: 0; + } +`; + +export const UserMenu = styled.div` + position: absolute; + top: 61px; + right: 0; + width: 213px; + background-color: ${props => props.theme.cardBackground}; + border-radius: 10px; + box-shadow: 0px 10px 39px rgba(26, 56, 101, 0.21); + padding: 34px; + z-index: 10; + text-align: center; +`; + +export const UserName = styled.p` + font-weight: 500; + font-size: 14px; + line-height: 21px; + color: ${props => props.theme.textPrimary}; + margin-bottom: 4px; +`; + +export const UserEmail = styled.p` + font-size: 14px; + line-height: 21px; + color: ${props => props.theme.textSecondary}; + margin-bottom: 10px; +`; + +export const ThemeToggleWrapper = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 15px; +`; + +export const ThemeToggle = styled.label` + position: relative; + display: inline-block; + width: 32px; + height: 20px; +`; + +export const ToggleInput = styled.input` + opacity: 0; + width: 0; + height: 0; + + &:checked + span { + background-color: #565EEF; + } + + &:checked + span:before { + transform: translateX(12px); + } +`; + +export const ToggleSlider = styled.span` + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #C1C1C1; + transition: .4s; + border-radius: 34px; + + &:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 2px; + bottom: 2px; + background-color: white; + transition: .4s; + border-radius: 50%; + } +`; + +export const ExitButton = styled.button` + width: 72px; + height: 30px; + background-color: transparent; + border: 1px solid ${props => props.theme.primary || '#565EEF'}; + border-radius: 4px; + color: ${props => props.theme.primary || '#565EEF'}; + font-size: 14px; + line-height: 21px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.3s ease, color 0.3s ease; + + &:hover { + background-color: ${props => props.theme.primary || '#565EEF'}; + color: ${props => props.theme.cardBackground || '#FFFFFF'}; + } +`; + +export const LogoLink = styled.a` + display: block; +`; + +export const LogoImage = styled.img` + width: 85px; + display: ${props => props.$isLight ? 'block' : 'none'}; + + ${props => props.$isDark && ` + display: none; + `} + + @media (prefers-color-scheme: dark) { + display: ${props => props.$isDark ? 'block' : 'none'}; + } +`; \ No newline at end of file diff --git a/skypro-kanban/src/components/Main/Main.jsx b/skypro-kanban/src/components/Main/Main.jsx index 05ffb89..5114679 100644 --- a/skypro-kanban/src/components/Main/Main.jsx +++ b/skypro-kanban/src/components/Main/Main.jsx @@ -1,44 +1,38 @@ import React from 'react'; import Column from '../Column/Column'; -import '../../App.css'; - -const statusList = ["БЕЗ СТАТУСА", "НУЖНО СДЕЛАТЬ", "В РАБОТЕ", "ТЕСТИРОВАНИЕ", "ГОТОВО"]; - -const tasks = [ - { id: 1, title: "Название задачи", category: "Web Design", status: "БЕЗ СТАТУСА", date: "30.10.23" }, - { id: 2, title: "Название задачи", category: "Research", status: "БЕЗ СТАТУСА", date: "31.10.23" }, - { id: 3, title: "Название задачи", category: "Web Design", status: "БЕЗ СТАТУСА", date: "30.10.23" }, - { id: 4, title: "Название задачи", category: "Copywriting", status: "БЕЗ СТАТУСА", date: "31.10.23" }, - { id: 5, title: "Название задачи", category: "Web Design", status: "БЕЗ СТАТУСА", date: "31.10.23" }, - - { id: 6, title: "Название задачи", category: "Research", status: "НУЖНО СДЕЛАТЬ", date: "30.10.23" }, - - { id: 7, title: "Название задачи", category: "Research", status: "В РАБОТЕ", date: "30.10.23" }, - { id: 8, title: "Название задачи", category: "Copywriting", status: "В РАБОТЕ", date: "30.10.23" }, - { id: 9, title: "Название задачи", category: "Web Design", status: "В РАБОТЕ", date: "30.10.23" }, - - { id: 10, title: "Название задачи", category: "Research", status: "ТЕСТИРОВАНИЕ", date: "01.11.23" }, - - { id: 11, title: "Название задачи", category: "Research", status: "ГОТОВО", date: "01.11.23" }, +import { MainWrapper, MainBlock, MainContent } from './MainStyles'; +import styled from 'styled-components'; +import { containerStyles } from "../../styles/CommonStyles"; + +const Container = styled.div` + ${containerStyles} +`; + +const statusList = [ + "Без статуса", + "Нужно сделать", + "В работе", + "Тестирование", + "Готово", ]; -function Main() { +function Main({ cards }) { return ( -
-
-
-
- {statusList.map(status => ( + + + + + {statusList.map((status) => ( task.status === status)} + tasks={cards.filter((card) => card.status.toLowerCase() === status.toLowerCase())} /> ))} -
-
-
-
+ + + + ); } diff --git a/skypro-kanban/src/components/Main/MainStyles.js b/skypro-kanban/src/components/Main/MainStyles.js new file mode 100644 index 0000000..7a3d8a6 --- /dev/null +++ b/skypro-kanban/src/components/Main/MainStyles.js @@ -0,0 +1,17 @@ +import styled from 'styled-components'; + +export const MainWrapper = styled.main` + width: 100%; + background-color: ${props => props.theme.background}; +`; + +export const MainBlock = styled.div` + width: 100%; + margin: 0 auto; + padding: 25px 0 49px; +`; + +export const MainContent = styled.div` + width: 100%; + display: flex; +`; \ No newline at end of file diff --git a/skypro-kanban/src/components/Popups/PopNewCard/PopNewCard.jsx b/skypro-kanban/src/components/Popups/PopNewCard/PopNewCard.jsx index bb3fa3f..c11a503 100644 --- a/skypro-kanban/src/components/Popups/PopNewCard/PopNewCard.jsx +++ b/skypro-kanban/src/components/Popups/PopNewCard/PopNewCard.jsx @@ -1,8 +1,26 @@ -import React from 'react'; +import React, { useState } from 'react'; import Calendar from '../../Calendar/Calendar'; import '../../../App.css'; -function PopNewCard() { +function PopNewCard({ onCardAdd }) { + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [category, setCategory] = useState('Web Design'); + + const handleCreateNewTask = (e) => { + e.preventDefault(); + onCardAdd({ + id: Date.now(), + title: title, + topic: topic, + date: new Date().toLocaleDateString('ru-RU'), + status: "Без статуса" + }); + setTitle(''); + setDescription(''); + setCategory('Web Design'); + }; + return (
@@ -14,11 +32,27 @@ function PopNewCard() {
- + setTitle(e.target.value)} + autoFocus + />
-