From a85c4154a500b0e2137132e1b7ec1efe67f93a4d Mon Sep 17 00:00:00 2001 From: Dollerino Date: Fri, 14 Aug 2026 18:20:18 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-1077=20-=20=D0=94?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20P8PHeader=20=D0=B8?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B4=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B3=D0=BE=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/p8p_dialog.js | 69 ++++-- app/components/p8p_header.js | 34 +++ .../components/p8p_header_button_base.js | 79 +++++++ .../components/p8p_header_filter_item.js | 78 +++++++ .../p8p_header/components/p8p_header_item.js | 35 +++ .../p8p_header/p8p_header_button.js | 39 ++++ .../p8p_header/p8p_header_constants.js | 40 ++++ .../p8p_header/p8p_header_date_picker.js | 112 ++++++++++ .../p8p_header/p8p_header_dictionary.js | 73 +++++++ app/components/p8p_header/p8p_header_field.js | 82 +++++++ .../p8p_header/p8p_header_filter.js | 125 +++++++++++ app/components/p8p_header/p8p_header_hooks.js | 121 +++++++++++ .../p8p_header/p8p_header_indicator.js | 63 ++++++ .../p8p_header/p8p_header_selector.js | 103 +++++++++ app/components/p8p_header/p8p_header_text.js | 63 ++++++ app/components/p8p_header/p8p_header_utils.js | 200 ++++++++++++++++++ app/theme/constants.js | 15 ++ app/theme/p8p_components.js | 8 +- app/theme/p8p_palette.js | 12 ++ app/theme/p8p_typography.js | 8 + app/theme/styles/box.js | 118 +++++++++-- app/theme/styles/common.js | 32 +-- app/theme/styles/form_control.js | 30 +++ app/theme/styles/grid.js | 19 ++ app/theme/styles/paper.js | 7 +- app/theme/styles/stack.js | 70 +++++- app/theme/styles/typography.js | 58 ++++- app/theme/utils.js | 2 +- app/theme/variants/p8p_button_variants.js | 37 +++- app/theme/variants/p8p_card_variants.js | 12 +- app/theme/variants/p8p_container_variants.js | 12 +- .../variants/p8p_dialog_actions_variants.js | 31 +++ .../variants/p8p_dialog_content_variants.js | 37 +++- .../variants/p8p_dialog_title_variants.js | 10 +- app/theme/variants/p8p_drawer_variants.js | 8 +- app/theme/variants/p8p_fab_variants.js | 42 ++++ app/theme/variants/p8p_grid_variants.js | 35 +-- .../variants/p8p_icon_button_variants.js | 24 ++- app/theme/variants/p8p_icon_variants.js | 36 ++-- app/theme/variants/p8p_list_item_variants.js | 37 ++++ app/theme/variants/p8p_list_variants.js | 20 +- app/theme/variants/p8p_menu_item_variants.js | 6 +- app/theme/variants/p8p_select_variants.js | 11 +- app/theme/variants/p8p_table_head_variants.js | 6 +- app/theme/variants/p8p_text_field_variants.js | 11 +- 45 files changed, 1895 insertions(+), 175 deletions(-) create mode 100644 app/components/p8p_header.js create mode 100644 app/components/p8p_header/components/p8p_header_button_base.js create mode 100644 app/components/p8p_header/components/p8p_header_filter_item.js create mode 100644 app/components/p8p_header/components/p8p_header_item.js create mode 100644 app/components/p8p_header/p8p_header_button.js create mode 100644 app/components/p8p_header/p8p_header_constants.js create mode 100644 app/components/p8p_header/p8p_header_date_picker.js create mode 100644 app/components/p8p_header/p8p_header_dictionary.js create mode 100644 app/components/p8p_header/p8p_header_field.js create mode 100644 app/components/p8p_header/p8p_header_filter.js create mode 100644 app/components/p8p_header/p8p_header_hooks.js create mode 100644 app/components/p8p_header/p8p_header_indicator.js create mode 100644 app/components/p8p_header/p8p_header_selector.js create mode 100644 app/components/p8p_header/p8p_header_text.js create mode 100644 app/components/p8p_header/p8p_header_utils.js create mode 100644 app/theme/constants.js create mode 100644 app/theme/styles/form_control.js create mode 100644 app/theme/styles/grid.js create mode 100644 app/theme/variants/p8p_dialog_actions_variants.js create mode 100644 app/theme/variants/p8p_fab_variants.js create mode 100644 app/theme/variants/p8p_list_item_variants.js diff --git a/app/components/p8p_dialog.js b/app/components/p8p_dialog.js index c453588..e0d265f 100644 --- a/app/components/p8p_dialog.js +++ b/app/components/p8p_dialog.js @@ -9,12 +9,16 @@ import React, { useEffect, useState } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты +import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Box, Typography, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты import { BUTTONS } from "../../app.text"; //Общие текстовые ресурсы import { P8P_INPUT, P8PInput } from "./p8p_input"; //Поле ввода -import { P8P_DIALOG_CONTENT_VARIANT } from "../theme/variants/p8p_dialog_content_variants"; //Варианты содержимого диалога -import { P8P_BUTTON_VARIANT } from "../theme/variants/p8p_button_variants"; //Варианты кнопок import { P8P_DIALOG_TITLE_VARIANT } from "../theme/variants/p8p_dialog_title_variants"; //Варианты заголовков диалога +import { P8P_DIALOG_CONTENT_VARIANT } from "../theme/variants/p8p_dialog_content_variants"; //Варианты содержимого диалога +import { P8P_DIALOG_ACTIONS_VARIANT } from "../theme/variants/p8p_dialog_actions_variants"; //Варианты действий диалога +import { P8P_BUTTON_VARIANT } from "../theme/variants/p8p_button_variants"; //Варианты кнопок +import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов +import { P8P_ICON_BUTTON_VARIANT } from "../theme/variants/p8p_icon_button_variants"; //Варианты кнопок-иконок +import { P8P_BOX_DIALOG_TITLE } from "../theme/styles/box"; //Стили контейнеров //--------- //Константы @@ -49,6 +53,8 @@ const P8PDialog = ({ inputs, children, okDisabled = false, + paddingDisabled = false, + actionsDisabled = false, scrollContent = true, onOk, onCancel, @@ -89,30 +95,47 @@ const P8PDialog = ({ //Формирование представления return ( - {title} - + + + {/* Пустая ячейка для баланса */} + + {title} + + + + close + + + + + {inputsState.map((input, i) => ( ))} {children} - - {onClose && ( - - )} - {onCancel && ( - - )} - {onOk && ( - - )} - + {!actionsDisabled ? ( + + {onClose && ( + + )} + {onCancel && ( + + )} + {onOk && ( + + )} + + ) : null} ); }; @@ -125,6 +148,8 @@ P8PDialog.propTypes = { inputs: PropTypes.arrayOf(PropTypes.shape(P8P_INPUT)), children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]), okDisabled: PropTypes.bool, + paddingDisabled: PropTypes.bool, + actionsDisabled: PropTypes.bool, scrollContent: PropTypes.bool, onOk: PropTypes.func, onCancel: PropTypes.func, diff --git a/app/components/p8p_header.js b/app/components/p8p_header.js new file mode 100644 index 0000000..a075f9c --- /dev/null +++ b/app/components/p8p_header.js @@ -0,0 +1,34 @@ +/* + Парус 8 - Панели мониторинга + Компонент: Заголовок +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Box } from "@mui/material"; //Интерфейсные элементы +import { P8P_BOX_HEADER } from "../theme/styles/box"; //Стили контейнеров + +//----------- +//Тело модуля +//----------- + +//Заголовок +const P8PHeader = ({ children, isFixed }) => { + return {children}; +}; + +//Контроль свойств - Заголовок +P8PHeader.propTypes = { + children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]), + isFixed: PropTypes.bool +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeader }; diff --git a/app/components/p8p_header/components/p8p_header_button_base.js b/app/components/p8p_header/components/p8p_header_button_base.js new file mode 100644 index 0000000..5b64e57 --- /dev/null +++ b/app/components/p8p_header/components/p8p_header_button_base.js @@ -0,0 +1,79 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Базовая кнопка +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Icon, Typography, Stack, IconButton, Button } from "@mui/material"; //Интерфейсные элементы +import { P8P_TYPOGRAPHY_VARIANT } from "../../../theme/p8p_typography"; //Варианты шрифтов +import { P8P_TYPOGRAPHY_MAX_LINES } from "../../../theme/styles/typography"; //Стили текста +import { P8P_STACK_HEADER_WITH_CLEAR } from "../../../theme/styles/stack"; // //Стили для групповой информации +import { P8P_ICON_VARIANT } from "../../../theme/variants/p8p_icon_variants"; //Варианты иконок +import { P8P_COMPONENT_SIZE } from "../../../theme/constants"; //Общие константы стилей +import { P8P_BUTTON_VARIANT } from "../../../theme/variants/p8p_button_variants"; //Варианты кнопок +import { P8PHeaderItem } from "./p8p_header_item"; //Элемент заголовка + +//----------- +//Тело модуля +//----------- + +//Базовая кнопка +const P8PHeaderButtonBase = ({ icon, value, width, size = P8P_COMPONENT_SIZE.LARGE, iconSize, onClick, onClear, customButtonContent }) => { + console.log("rerender"); + //При нажатии на кнопку + const handleClick = () => onClick && onClick(); + + //При необходимости очистки + const handleClear = () => onClear && onClear(); + + //Содержимое кнопки + const buttonConent = customButtonContent || ( + + {icon ? {icon} : null} + {value ? ( + + {value} + + ) : null} + + ); + + //Генерация содержимого + return ( + + + + {onClear ? ( + + cancel + + ) : null} + + + ); +}; + +//Контроль свойств - Базовая кнопка +P8PHeaderButtonBase.propTypes = { + icon: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + iconSize: PropTypes.oneOf(Object.values(P8P_COMPONENT_SIZE)), + size: PropTypes.oneOf(Object.values(P8P_COMPONENT_SIZE)), + onClick: PropTypes.func.isRequired, + onClear: PropTypes.func, + customButtonContent: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]) +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderButtonBase }; diff --git a/app/components/p8p_header/components/p8p_header_filter_item.js b/app/components/p8p_header/components/p8p_header_filter_item.js new file mode 100644 index 0000000..abea3b7 --- /dev/null +++ b/app/components/p8p_header/components/p8p_header_filter_item.js @@ -0,0 +1,78 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Элемент фильтра +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Icon, Stack, Typography, IconButton } from "@mui/material"; //Интерфейсные элементы +import { P8P_TYPOGRAPHY_VARIANT } from "../../../theme/p8p_typography"; //Варианты шрифтов +import { P8P_TYPOGRAPHY_MAX_LINES } from "../../../theme/styles/typography"; //Стили текста +import { P8P_STACK_HEADER_FILTER, P8P_STACK_HEADER_FILTER_CONTAINER } from "../../../theme/styles/stack"; //Стили для групповой информации +import { P8P_ICON_VARIANT } from "../../../theme/variants/p8p_icon_variants"; //Варианты иконок + +//----------- +//Тело модуля +//----------- + +//Элемент фильтра +const P8PHeaderFilterItem = ({ filter, onClick, onDelete }) => { + //Признак возможности нажатия + const isClickable = onDelete || onClick ? true : false; + + //При нажатии на содержимое + const handleFilterClick = () => onClick && onClick(filter); + + //При удалении фильтра + const handleFilterDelete = () => onDelete && onDelete(filter); + + //Генерация содержимого + return ( + + (onClick ? handleFilterClick : null)}> + + {filter.caption} + + {!React.isValidElement(filter.value) ? ( + + {filter.value} + + ) : ( + filter.value + )} + + {onDelete ? ( + + cancel + + ) : null} + + ); +}; + +//Контроль свойств - Элемент фильтра +P8PHeaderFilterItem.propTypes = { + filter: PropTypes.object, + onClick: PropTypes.func, + onDelete: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderFilterItem }; diff --git a/app/components/p8p_header/components/p8p_header_item.js b/app/components/p8p_header/components/p8p_header_item.js new file mode 100644 index 0000000..32d05c9 --- /dev/null +++ b/app/components/p8p_header/components/p8p_header_item.js @@ -0,0 +1,35 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Элемент заголовка +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Box } from "@mui/material"; //Интерфейсные элементы +import { P8P_BOX_HEADER_ITEM } from "../../../theme/styles/box"; //Стили контейнеров + +//----------- +//Тело модуля +//----------- + +//Элемент заголовка +const P8PHeaderItem = ({ width, children }) => { + //Генерация содержимого + return {children}; +}; + +//Контроль свойств - Элемент заголовка +P8PHeaderItem.propTypes = { + width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]) +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderItem }; diff --git a/app/components/p8p_header/p8p_header_button.js b/app/components/p8p_header/p8p_header_button.js new file mode 100644 index 0000000..7b889f0 --- /dev/null +++ b/app/components/p8p_header/p8p_header_button.js @@ -0,0 +1,39 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Кнопка +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { P8P_COMPONENT_SIZE } from "../../theme/constants"; //Общие константы стилей +import { P8PHeaderButtonBase } from "./components/p8p_header_button_base"; //Базовая кнопка заголовка + +//----------- +//Тело модуля +//----------- + +//Кнопка +const P8PHeaderButton = ({ icon, value, width, size = P8P_COMPONENT_SIZE.LARGE, iconSize, onClick }) => { + //Генерация содержимого + return ; +}; + +//Контроль свойств - Кнопка +P8PHeaderButton.propTypes = { + icon: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + iconSize: PropTypes.oneOf(Object.values(P8P_COMPONENT_SIZE)), + size: PropTypes.oneOf(Object.values(P8P_COMPONENT_SIZE)), + onClick: PropTypes.func.isRequired +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderButton }; diff --git a/app/components/p8p_header/p8p_header_constants.js b/app/components/p8p_header/p8p_header_constants.js new file mode 100644 index 0000000..33ef5b2 --- /dev/null +++ b/app/components/p8p_header/p8p_header_constants.js @@ -0,0 +1,40 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Константы +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import PropTypes from "prop-types"; //Контроль свойств компонента +import { STATE } from "../../../app.text"; //Текстовые ресурсы и константы + +//----------- +//Тело модуля +//----------- + +//Минимальная ширина при наличии элементов +const P8P_HEADER_MIN_FILTER_WIDTH = 125; + +//Структура элемента описания фильтра +const P8P_HEADER_FILTER_SHAPE = PropTypes.shape({ + name: PropTypes.string, + caption: PropTypes.string.isRequired, + value: PropTypes.any, + width: PropTypes.string +}); + +//Состояния индикатора +const P8P_HEADER_INDICATOR_STATE = { + UNDEFINED: STATE.UNDEFINED, + OK: STATE.OK, + WARN: STATE.WARN, + ERR: STATE.ERR +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8P_HEADER_MIN_FILTER_WIDTH, P8P_HEADER_FILTER_SHAPE, P8P_HEADER_INDICATOR_STATE }; diff --git a/app/components/p8p_header/p8p_header_date_picker.js b/app/components/p8p_header/p8p_header_date_picker.js new file mode 100644 index 0000000..4d8d77a --- /dev/null +++ b/app/components/p8p_header/p8p_header_date_picker.js @@ -0,0 +1,112 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Выбор даты +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useRef } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import dayjs from "dayjs"; //Работа с датами +import { TextField, Typography, Stack } from "@mui/material"; //Интерфейсные элементы +import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов +import { P8P_TEXT_FIELD_VARIANT } from "../../theme/variants/p8p_text_field_variants"; //Варианты полей ввода +import { P8P_TYPOGRAPHY_MAX_LINES } from "../../theme/styles/typography"; //Стили шрифтов +import { formatDateRF, formatDateTimeRF } from "../../core/utils"; //Общие вспомогательные функции приложения +import { P8P_COMPONENT_SIZE } from "../../theme/constants"; //Общие константы стилей +import { P8PHeaderButtonBase } from "./components/p8p_header_button_base"; //Базовая кнопка заголовка + +//--------- +//Константы +//--------- + +//Типы даты +const P8P_HEADER_DATE_PICKER_TYPE = { + DATE: "date", + DATETIME: "datetime-local", + MONTH: "month", + WEEK: "week", + TIME: "time" +}; + +//Форматирование значения даты +const P8P_HEADER_DATE_PICKER_CONVERTER = { + [P8P_HEADER_DATE_PICKER_TYPE.DATE]: date => formatDateRF(date), + [P8P_HEADER_DATE_PICKER_TYPE.DATETIME]: date => formatDateTimeRF(date), + [P8P_HEADER_DATE_PICKER_TYPE.MONTH]: date => dayjs(date).locale("ru").format("MMMM YYYY"), + [P8P_HEADER_DATE_PICKER_TYPE.WEEK]: date => { + //Определяем неделю и год + const [year, week] = date.split("-W"); + //Строковый формат + return `${week} неделя ${year}`; + }, + [P8P_HEADER_DATE_PICKER_TYPE.TIME]: date => date +}; + +//----------- +//Тело модуля +//----------- + +//Выбор даты +const P8PHeaderDatePicker = ({ value, placeholder, type = "date", width, onSelect, onClear }) => { + //Ссылка на поле ввода + const inputRef = useRef(null); + + //При нажатии на кнопку выбора + const handleButtonClick = () => inputRef.current.showPicker(); + + //При смене значения + const onChange = e => onSelect && onSelect(e.target.value); + + //Собственное представление кнопки + const buttonContent = ( + + + + {value ? P8P_HEADER_DATE_PICKER_CONVERTER[type](value) : placeholder} + + + ); + + //Генерация содержимого + return ( + + ); +}; + +//Контроль свойств - Выбор даты +P8PHeaderDatePicker.propTypes = { + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + placeholder: PropTypes.string.isRequired, + type: PropTypes.oneOf(Object.values(P8P_HEADER_DATE_PICKER_TYPE)), + width: PropTypes.string, + onSelect: PropTypes.func, + onClear: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderDatePicker, P8P_HEADER_DATE_PICKER_TYPE }; diff --git a/app/components/p8p_header/p8p_header_dictionary.js b/app/components/p8p_header/p8p_header_dictionary.js new file mode 100644 index 0000000..ceba724 --- /dev/null +++ b/app/components/p8p_header/p8p_header_dictionary.js @@ -0,0 +1,73 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Плавающая кнопка действия +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useContext } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { ApplicationCtx } from "../../context/application"; //Контекст приложения +import { P8P_COMPONENT_SIZE } from "../../theme/constants"; //Общие константы стилей +import { P8PHeaderButtonBase } from "./components/p8p_header_button_base"; //Общие константы стилей + +//--------- +//Константы +//--------- + +//Структура элемента входного параметра +const P8P_HEADER_DICT_INPUT_PRMS = PropTypes.shape({ + name: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired +}); + +//----------- +//Тело модуля +//----------- + +//Выбор значения из словаря +const P8PHeaderDictionary = ({ value, placeholder, unitCode, showMethod = "main", inputParameters, width, onSelect, onClear }) => { + //Подключение к контексту приложения + const { pOnlineShowDictionary } = useContext(ApplicationCtx); + + //При нажатии на кнопку + const handleButtonClick = () => { + pOnlineShowDictionary({ + unitCode, + showMethod, + inputParameters, + callBack: res => res.success && onSelect && onSelect(res.outParameters) + }); + }; + + //Формирование представления + return ( + + ); +}; + +//Контроль свойств - Выбор значения из словаря +P8PHeaderDictionary.propTypes = { + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + placeholder: PropTypes.string.isRequired, + unitCode: PropTypes.string.isRequired, + showMethod: PropTypes.string, + inputParameters: PropTypes.arrayOf(P8P_HEADER_DICT_INPUT_PRMS), + width: PropTypes.string, + onSelect: PropTypes.func, + onClear: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderDictionary }; diff --git a/app/components/p8p_header/p8p_header_field.js b/app/components/p8p_header/p8p_header_field.js new file mode 100644 index 0000000..a69d55b --- /dev/null +++ b/app/components/p8p_header/p8p_header_field.js @@ -0,0 +1,82 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Поле ввода +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { TextField, InputAdornment, Icon, FormControl, IconButton } from "@mui/material"; //Интерфейсные элементы +import { P8P_FORM_CONTROL_HEADER_FIELD } from "../../theme/styles/form_control"; //Стили контекста полей ввода +import { P8P_TEXT_FIELD_VARIANT } from "../../theme/variants/p8p_text_field_variants"; //Варианты полей ввода +import { P8PHeaderItem } from "./components/p8p_header_item"; //Элемент заголовка + +//--------- +//Константы +//--------- + +//Структура элемента доп. иконки поля ввода +const P8P_HEADER_FIELD_ADORNMENT_SHAPE = PropTypes.shape({ + icon: PropTypes.string.isRequired, + disabled: PropTypes.bool, + onClick: PropTypes.func +}); + +//----------- +//Тело модуля +//----------- + +//Поле ввода +const P8PHeaderField = ({ value, placeholder, type = "text", endAdornments = [], width, onChange }) => { + //При смене значения + const handleChange = e => onChange && onChange(e.target.value); + + //Генерация содержимого + return ( + + + 0 ? ( + + {endAdornments.map((item, index) => ( + item.onClick(e)} key={index} disabled={item.disabled}> + {item.icon} + + ))} + + ) : null + }} + /> + + + ); +}; + +//Контроль свойств - Поле ввода +P8PHeaderField.propTypes = { + value: PropTypes.any, + placeholder: PropTypes.string.isRequired, + type: PropTypes.string, + endAdornments: PropTypes.arrayOf(P8P_HEADER_FIELD_ADORNMENT_SHAPE), + width: PropTypes.string, + onChange: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderField }; diff --git a/app/components/p8p_header/p8p_header_filter.js b/app/components/p8p_header/p8p_header_filter.js new file mode 100644 index 0000000..88d3abf --- /dev/null +++ b/app/components/p8p_header/p8p_header_filter.js @@ -0,0 +1,125 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Фильтры +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Box, Icon, Grid, IconButton, Popover, List, ListItem } from "@mui/material"; //Интерфейсные элементы +import { P8P_GRID_VARIANT } from "../../theme/variants/p8p_grid_variants"; //Варианты сеток +import { P8P_ICON_BUTTON_VARIANT } from "../../theme/variants/p8p_icon_button_variants"; //Варианты кнопок-иконок +import { P8P_BOX_HEADER_FILTER, P8P_BOX_HEADER_FILTER_GRP } from "../../theme/styles/box"; //Стили контейнеров +import { P8P_LIST_VARIANT } from "../../theme/variants/p8p_list_variants"; //Варианты списка +import { P8P_LIST_ITEM_VARIANT } from "../../theme/variants/p8p_list_item_variants"; //Варианты элемента списка +import { P8PHeaderFilterItem } from "./components/p8p_header_filter_item"; //Элемент фильтра заголовка +import { useP8PHeaderFilter } from "./p8p_header_hooks"; //Вспомогательные хуки фильтра +import { P8P_GRID_HEADER_FILTER_ITEM } from "../../theme/styles/grid"; //Стили адаптивного контейнера +import { P8P_HEADER_FILTER_SHAPE } from "./p8p_header_constants"; //Константы заголовка + +//----------- +//Тело модуля +//----------- + +//Фильтры +const P8PHeaderFilter = ({ filters, width, onClick, onDelete, showEmpty = true, maxDisplay = null }) => { + //Собственное состояние - состояние фильтра + const { gridRef, anchorEl, allowedFilters, visibleCount, isOverflowed, isLessMinWidth, handleFilterMoreOpen, handleFilterMoreClose } = + useP8PHeaderFilter({ filters, maxDisplay }); + + //Флаг отображения выпадающего списка + const open = Boolean(anchorEl); + //Флаг органичения отображения + const isLimited = maxDisplay > 0; + //Скрытые фильтры + const hiddenFilters = filters.slice(visibleCount); + + //При удалении фильтра + const handleFilterDelete = filter => onDelete && onDelete({ filter }); + + //При нажатии на фильтр + const handleFilterClick = filter => onClick && onClick({ filter }); + + //Генерация содержимого + return ( + <> + {showEmpty || allowedFilters.length > 0 ? ( + + + + {allowedFilters.map((filter, index) => ( + + + + ))} + + + {isOverflowed && ( + + tune + + )} + + ) : null} + + + {hiddenFilters.map((filter, index) => ( + + + + ))} + + + + ); +}; + +//Контроль свойств - Фильтры +P8PHeaderFilter.propTypes = { + filters: PropTypes.arrayOf(P8P_HEADER_FILTER_SHAPE), + width: PropTypes.string, + onClick: PropTypes.func, + onDelete: PropTypes.func, + showEmpty: PropTypes.bool, + maxDisplay: PropTypes.number +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderFilter }; diff --git a/app/components/p8p_header/p8p_header_hooks.js b/app/components/p8p_header/p8p_header_hooks.js new file mode 100644 index 0000000..0cfb305 --- /dev/null +++ b/app/components/p8p_header/p8p_header_hooks.js @@ -0,0 +1,121 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Хуки для заголовка +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import { useState, useEffect, useCallback, useRef, useMemo } from "react"; //Классы React +import { P8P_HEADER_MIN_FILTER_WIDTH } from "./p8p_header_constants"; //Константы заголовка + +//----------- +//Тело модуля +//----------- + +//Кастомный хук для определения информации об отображении +const useP8PHeaderVisibleInfo = (containerRef, maxDisplay, totalFilters) => { + //Отображаемое количество + const [visibleCount, setVisibleCount] = useState(maxDisplay > 0 ? maxDisplay : 0); + //Признак переполненности + const [isOverflowed, setIsOverflowed] = useState(false); + //Признак уменьшения меньше минимального значения + const [isLessMinWidth, setIsLessMinWidth] = useState(false); + + //Пересчет количество отображаемых + const recalcVisibleCount = useCallback(container => { + //Определяем дочерние элементы + const items = container.children; + //Определяем параметры контейнера + const containerRect = container.getBoundingClientRect(); + //Если блок меньше минимального значения + if (containerRect.width < P8P_HEADER_MIN_FILTER_WIDTH && items.length > 0) { + //Информируем, что невозможно показать + setVisibleCount(0); + setIsOverflowed(true); + setIsLessMinWidth(true); + return; + } + //Обнуляем счетчик видимых + let visible = 0; + //Обходим дочерние элменты + for (let i = 0; i < items.length; i++) { + //Определяем параметры элемента + const itemRect = items[i].getBoundingClientRect(); + //Проверяем, полностью ли элемент виден в контейнере + if (itemRect.bottom <= containerRect.bottom) { + visible++; + } else { + //Если один элемент скрыт, то и все последующие скрыты (при row-direction) + break; + } + } + //Устанавливаем отображаемых + setVisibleCount(visible); + setIsOverflowed(visible < items.length); + setIsLessMinWidth(false); + }, []); + + //При открытии страницы + useEffect(() => { + //Определяем контейнер + const container = containerRef.current; + //Если контейнер не определен или установлено максимально отображение - не отслеживаем + if (!container || maxDisplay > 0) { + setIsOverflowed(maxDisplay < totalFilters); + return; + } + //Пересчет количество отображаемых + recalcVisibleCount(container); + //Определяем отслеживание + const observer = new ResizeObserver(() => { + //Пересчет количество отображаемых + recalcVisibleCount(container); + }); + //Подключаем отслеживание + observer.observe(container); + //При закрытии компонента + return () => observer.disconnect(); + }, [containerRef, maxDisplay, recalcVisibleCount, totalFilters]); + //Возвращаем данные + return { visibleCount, isOverflowed, isLessMinWidth }; +}; + +//Хук состояния фильтра +const useP8PHeaderFilter = ({ filters, maxDisplay }) => { + //Собственное состояние - контейнер элементов + const gridRef = useRef(null); + + //Собственное состояние - элемент выпадающего списка + const [anchorEl, setAnchorEl] = useState(null); + //Собственное состояние - информация об отображении + const { visibleCount, isOverflowed, isLessMinWidth } = useP8PHeaderVisibleInfo(gridRef, maxDisplay, filters.length); + + //Отображаемые фильтры + const allowedFilters = useMemo(() => { + if (Array.isArray(filters) && filters.length > 0) { + return filters.slice(0, maxDisplay || filters.length); + } else { + return []; + } + }, [filters, maxDisplay]); + + //По нажатию на меню скрытых элементов + const handleFilterMoreOpen = event => { + setAnchorEl(event.currentTarget); + }; + + //При закрытии меню скрытых элементов + const handleFilterMoreClose = () => { + setAnchorEl(null); + }; + + return { gridRef, anchorEl, allowedFilters, visibleCount, isOverflowed, isLessMinWidth, handleFilterMoreOpen, handleFilterMoreClose }; +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { useP8PHeaderFilter }; diff --git a/app/components/p8p_header/p8p_header_indicator.js b/app/components/p8p_header/p8p_header_indicator.js new file mode 100644 index 0000000..ba8cee2 --- /dev/null +++ b/app/components/p8p_header/p8p_header_indicator.js @@ -0,0 +1,63 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Индикатор +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Stack, Typography } from "@mui/material"; //Интерфейсные элементы +import { P8P_STACK_HEADER_INDICATOR } from "../../theme/styles/stack"; //Стили для групповой информации +import { TEXTS } from "../../../app.text"; //Текстовые ресурсы и константы +import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов +import { P8P_HEADER_INDICATOR_STATE } from "./p8p_header_constants"; //Константы заголовка +import { P8P_TYPOGRAPY_HDR_INDICATOR } from "../../theme/styles/typography"; //Стили текста +import { P8PHeaderItem } from "./components/p8p_header_item"; //Элемент заголовка + +//----------- +//Тело модуля +//----------- + +//Индикатор +const P8PHeaderIndicator = ({ caption, value, state = P8P_HEADER_INDICATOR_STATE.UNDEFINED, disableCaptionColor = false, width, color, onClick }) => { + //При нажатии на текст + const handleClick = () => onClick && onClick({ caption, value }); + + //Генерация содержимого + return ( + + + + {caption} + + + {[undefined, null, ""].includes(value) ? TEXTS.NO_DATA_FOUND_SHORT : value} + + + + ); +}; + +//Контроль свойств - Индикатор +P8PHeaderIndicator.propTypes = { + caption: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + state: PropTypes.oneOf(Object.values(P8P_HEADER_INDICATOR_STATE)), + disableCaptionColor: PropTypes.bool, + width: PropTypes.string, + color: PropTypes.string, + onClick: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderIndicator }; diff --git a/app/components/p8p_header/p8p_header_selector.js b/app/components/p8p_header/p8p_header_selector.js new file mode 100644 index 0000000..957b63b --- /dev/null +++ b/app/components/p8p_header/p8p_header_selector.js @@ -0,0 +1,103 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Выбор из выпадающего списка +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useMemo } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { FormControl, Select, MenuItem, Stack, Checkbox } from "@mui/material"; //Интерфейсные элементы +import { P8P_SELECT_VARIANT } from "../../theme/variants/p8p_select_variants"; //Варианты полей выбора (Select) +import { P8P_MENU_ITEM_VARIANT } from "../../theme/variants/p8p_menu_item_variants"; //Варианты элементов меню +import { P8P_FORM_CONTROL_HEADER_SELECTOR } from "../../theme/styles/form_control"; //Стили контекста полей ввода +import { P8PHeaderItem } from "./components/p8p_header_item"; //Элемент заголовка + +//--------- +//Константы +//--------- + +//Структура элемента выпадающего списка +const P8P_HEADER_SELECTOR_OPTION = PropTypes.shape({ + value: PropTypes.any.isRequired, + title: PropTypes.string.isRequired +}); + +//----------- +//Тело модуля +//----------- + +//Выбор из выпадающего списка +const P8PHeaderSelector = ({ value, placeholder, options = [], multiple = false, width, onSelect }) => { + //При нажатии на текст + const handleChange = e => onSelect && onSelect(e.target.value); + + //Отображаемое значение + const displayValue = useMemo(() => { + //Если это множественный выбор + if (multiple) { + //Нет значения + if (!value || value.length === 0) return placeholder; + //Собираем выбранные значения + return options + .filter(option => value.includes(option.value)) + .map(option => option.title) + .join(", "); + } else { + //Нет значения + if (!value) return placeholder; + //Определяем отображаемое + const option = options.find(option => option.value === value); + return option ? option.title : placeholder; + } + }, [value, placeholder, options, multiple]); + + //Генерация содержимого + return ( + + + + + + ); +}; + +//Контроль свойств - Выбор из выпадающего списка +P8PHeaderSelector.propTypes = { + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]), + placeholder: PropTypes.string.isRequired, + options: PropTypes.arrayOf(P8P_HEADER_SELECTOR_OPTION).isRequired, + multiple: PropTypes.bool, + width: PropTypes.string, + onSelect: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderSelector }; diff --git a/app/components/p8p_header/p8p_header_text.js b/app/components/p8p_header/p8p_header_text.js new file mode 100644 index 0000000..8112b32 --- /dev/null +++ b/app/components/p8p_header/p8p_header_text.js @@ -0,0 +1,63 @@ +/* + Парус 8 - Панели мониторинга - Заголовок + Компонент: Текст +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Typography, Stack } from "@mui/material"; //Интерфейсные элементы +import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов +import { P8P_TYPOGRAPHY_MAX_LINES } from "../../theme/styles/typography"; //Стили текста +import { P8P_STACK_HEADER_TEXT } from "../../theme/styles/stack"; //Стили продвинутого контейнера +import { P8PHeaderItem } from "./components/p8p_header_item"; //Элемент заголовка + +//----------- +//Тело модуля +//----------- + +//Текст +const P8PHeaderText = ({ title, subTitle, width, onClick, children }) => { + //При нажатии на текст + const handleClick = () => onClick && onClick({ title, subTitle }); + + //Определение максимального количества доступных строк + const maxLines = subTitle ? 1 : 2; + + //Отображение по умолчанию + const defaultView = ( + + + {title} + + {subTitle ? ( + + {subTitle} + + ) : null} + + ); + + //Содержимое компонента + const content = children || defaultView; + //Генерация содержимого + return {content}; +}; + +//Контроль свойств - Текст +P8PHeaderText.propTypes = { + title: PropTypes.string, + subTitle: PropTypes.string, + width: PropTypes.string, + onClick: PropTypes.func, + children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]) +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PHeaderText }; diff --git a/app/components/p8p_header/p8p_header_utils.js b/app/components/p8p_header/p8p_header_utils.js new file mode 100644 index 0000000..5d9231d --- /dev/null +++ b/app/components/p8p_header/p8p_header_utils.js @@ -0,0 +1,200 @@ +import React, { useState } from "react"; + +import { hasValue } from "../../core/utils"; +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Stack, Chip, Typography, Box } from "@mui/material"; //Интерфейсные компоненты +import { P8P_DATA_TYPES } from "../../core/data_types"; +import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; +import { P8P_BOX_HEADER_FILTER_CUSTOM } from "../../theme/styles/box"; +import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; +import { P8P_TYPOGRAPHY_MAX_LINES } from "../../theme/styles/typography"; +import { P8P_STACK_HEADER_FILTER } from "../../theme/styles/stack"; +import { P8PTableColumnFilterDialog } from "../p8p_table/p8p_table_column_filter_dialog"; + +const FilterComponent = ({ filter, columnDef, valueFromCaption, valueToCaption, valueFormatter, onFilterChanged }) => { + //Собственное состояние - фильтруемая колонка + const [filterColumn, setFilterColumn] = useState(null); + const isClickable = false; + + //Значения фильтра фильтруемой колонки + const [filterColumnFrom, filterColumnTo] = filterColumn + ? (() => { + return filter ? [filter.from == null ? "" : filter.from, filter.to == null ? "" : filter.to] : ["", ""]; + })() + : ["", ""]; + + //Отработка ввода значения фильтра колонки + const handleFilterOk = (columnName, from, to) => { + if (onFilterChanged) onFilterChanged({ columnName, from: from === "" ? null : from, to: to === "" ? null : to }); + setFilterColumn(null); + }; + + //Отработка очистки значения фильтра колонки + const handleFilterClear = columnName => { + if (onFilterChanged) onFilterChanged({ columnName, from: null, to: null }); + setFilterColumn(null); + }; + + //Отработка отмены ввода значения фильтра колонки + const handleFilterCancel = () => { + setFilterColumn(null); + }; + + return ( + <> + + + {columnDef.name} + + setFilterColumn(columnDef.name)}> + + {hasValue(filter.from) && !columnDef.values && columnDef.dataType != P8P_DATA_TYPES.STR + ? `${valueFromCaption.toLowerCase()} ` + : null} + {hasValue(filter.from) ? (valueFormatter ? valueFormatter({ value: filter.from, columnDef }) : filter.from) : null} + {hasValue(filter.to) && !columnDef.values && columnDef.dataType != P8P_DATA_TYPES.STR + ? ` ${valueToCaption.toLowerCase()} ` + : null} + {hasValue(filter.to) ? (valueFormatter ? valueFormatter({ value: filter.to, columnDef }) : filter.to) : null} + + + + {filterColumn ? ( + + ) : null} + + ); +}; + +//Контроль свойств - Текст +FilterComponent.propTypes = { + filter: PropTypes.object, + columnDef: PropTypes.object, + valueFromCaption: PropTypes.string, + valueToCaption: PropTypes.string, + valueFormatter: PropTypes.func, + onFilterChanged: PropTypes.func +}; + +//Форматирование фильтра таблицы +const formatFilterDataGrid = ({ + filters, + columnsDef, + valueFromCaption = P8P_DATA_GRID_CONFIG_PROPS.valueFromCaption, + valueToCaption = P8P_DATA_GRID_CONFIG_PROPS.valueToCaption, + valueFormatter, + onClick, + onFilterChanged, + objectsCopier +}) => { + //Форматируем фильтры под заголовок + const formattedFilters = filters.map(filter => { + //Определяем колонку + const columnDef = columnsDef.find(columnDef => columnDef.name == filter.name); + //Формирование содержимого фильтра + const buildFilterContent = () => { + //Инициализируем части + const parts = []; + //Если есть "Значение с" + if (hasValue(filter.from)) { + //Если необходимо добавить префикс + if (!columnDef.values && columnDef.dataType != P8P_DATA_TYPES.STR) { + parts.push(`${valueFromCaption.toLowerCase()} `); + } + //Добавляем "Значение с" + parts.push(valueFormatter ? valueFormatter({ value: filter.from, columnDef }) : filter.from); + } + //Если есть "Значение по" + if (hasValue(filter.to)) { + //Если необходимо добавить префикс + if (!columnDef.values && columnDef.dataType != P8P_DATA_TYPES.STR) { + parts.push(` ${valueToCaption.toLowerCase()} `); + } + //Добавляем "Значение по" + parts.push(valueFormatter ? valueFormatter({ value: filter.to, columnDef }) : filter.to); + } + //Возвращаем массив элементов + return parts; + }; + + //При изменении состояния фильтра + const handleFilterChanged = ({ columnName, from, to }) => { + let newFilters = objectsCopier(filters); + let curFilter = newFilters.find(f => f.name == columnName); + if (from == null && to == null && curFilter) newFilters.splice(newFilters.indexOf(curFilter), 1); + if ((from != null || to != null) && !curFilter) newFilters.push({ name: columnName, from, to }); + if ((from != null || to != null) && curFilter) { + curFilter.from = from; + curFilter.to = to; + } + if (onFilterChanged) onFilterChanged({ filters: newFilters }); + }; + //Инициализируем содержмое значения + const content = buildFilterContent(); + //Возвращаем результат + return { + caption: columnDef.caption, + // from: valueFormatter ? ( + // + // {React.Children.toArray(content)} + // + // ) : ( + // content.join("") + // ), + from: ( + + ), + customView: ( + + ), + onClick: () => onClick && onClick(columnDef.name) + }; + }); + return formattedFilters; +}; + +export const P8P_HEADER_FILTER_FORMAT = { + DATA_GRID: ({ + filters, + columnsDef, + valueFromCaption = P8P_DATA_GRID_CONFIG_PROPS.valueFromCaption, + valueToCaption = P8P_DATA_GRID_CONFIG_PROPS.valueToCaption, + valueFormatter, + onClick, + onFilterChanged, + objectsCopier + }) => formatFilterDataGrid({ filters, columnsDef, valueFromCaption, valueToCaption, valueFormatter, onClick, onFilterChanged, objectsCopier }) +}; diff --git a/app/theme/constants.js b/app/theme/constants.js new file mode 100644 index 0000000..87bc1de --- /dev/null +++ b/app/theme/constants.js @@ -0,0 +1,15 @@ +/* + Парус 8 - Панели мониторинга + Общие константы стилей +*/ + +//---------------- +//Интерфейс модуля +//---------------- + +//Размеры компонента +export const P8P_COMPONENT_SIZE = { + SMALL: "small", + MEDIUM: "medium", + LARGE: "large" +}; diff --git a/app/theme/p8p_components.js b/app/theme/p8p_components.js index bb1d27a..59cecfc 100644 --- a/app/theme/p8p_components.js +++ b/app/theme/p8p_components.js @@ -18,10 +18,12 @@ import { P8P_ICON_OVERRIDES } from "./variants/p8p_icon_variants"; //Расши import { P8P_ICON_BUTTON_OVERRIDES } from "./variants/p8p_icon_button_variants"; //Расширение IconButton import { P8P_TEXT_FIELD_OVERRIDES } from "./variants/p8p_text_field_variants"; //Расширение TextField import { P8P_LIST_OVERRIDES } from "./variants/p8p_list_variants"; //Расширение List +import { P8P_LIST_ITEM_OVERRIDES } from "./variants/p8p_list_item_variants"; //Расширение ListItem import { P8P_LIST_ITEM_TEXT_OVERRIDES } from "./variants/p8p_list_item_text_variants"; //Расширение ListItemText import { P8P_DIALOG_TITLE_OVERRIDES } from "./variants/p8p_dialog_title_variants"; //Расширение DialogTitle import { P8P_DIALOG_CONTENT_OVERRIDES } from "./variants/p8p_dialog_content_variants"; //Расширение DialogContent import { P8P_DIALOG_CONTENT_TEXT_OVERRIDES } from "./variants/p8p_dialog_content_text_variants"; //Расширение DialogContentText +import { P8P_DIALOG_ACTIONS_OVERRIDES } from "./variants/p8p_dialog_actions_variants"; //Расширение DialogActions import { P8P_DRAWER_OVERRIDES } from "./variants/p8p_drawer_variants"; //Расширение Drawer import { P8P_APP_BAR_OVERRIDES } from "./variants/p8p_app_bar_variants"; //Расширение AppBar import { P8P_GRID_OVERRIDES } from "./variants/p8p_grid_variants"; //Расширение Grid @@ -32,6 +34,7 @@ import { P8P_INPUT_OVERRIDES } from "./variants/p8p_input_variants"; //Расш import { P8P_INPUT_LABEL_OVERRIDES } from "./variants/p8p_input_label_variants"; //Расширение InputLable import { P8P_MENU_ITEM_OVERRIDES } from "./variants/p8p_menu_item_variants"; //Расширение MenuItem import { P8P_AUTOCOMPLETE_OVERRIDES } from "./variants/p8p_autocomplete_variants"; //Расширение Autocomplete +import { P8P_FAB_OVERRIDES } from "./variants/p8p_fab_variants"; //Расширение Fab //---------------- //Интерфейс модуля @@ -52,7 +55,9 @@ export const P8P_COMPONENTS = { MuiDialogTitle: P8P_DIALOG_TITLE_OVERRIDES, MuiDialogContent: P8P_DIALOG_CONTENT_OVERRIDES, MuiDialogContentText: P8P_DIALOG_CONTENT_TEXT_OVERRIDES, + MuiDialogActions: P8P_DIALOG_ACTIONS_OVERRIDES, MuiList: P8P_LIST_OVERRIDES, + MuiListItem: P8P_LIST_ITEM_OVERRIDES, MuiListItemText: P8P_LIST_ITEM_TEXT_OVERRIDES, MuiDrawer: P8P_DRAWER_OVERRIDES, MuiAppBar: P8P_APP_BAR_OVERRIDES, @@ -63,5 +68,6 @@ export const P8P_COMPONENTS = { MuiInputLabel: P8P_INPUT_LABEL_OVERRIDES, MuiInput: P8P_INPUT_OVERRIDES, MuiMenuItem: P8P_MENU_ITEM_OVERRIDES, - MuiAutocomplete: P8P_AUTOCOMPLETE_OVERRIDES + MuiAutocomplete: P8P_AUTOCOMPLETE_OVERRIDES, + MuiFab: P8P_FAB_OVERRIDES }; diff --git a/app/theme/p8p_palette.js b/app/theme/p8p_palette.js index d4fcb21..4994351 100644 --- a/app/theme/p8p_palette.js +++ b/app/theme/p8p_palette.js @@ -57,6 +57,11 @@ export const P8P_PALETTE = { secondary: "#F8FAFD", tableHeader: "#E6EAF3" }, + P8PScroll: { + track: "#EBEBEB", + thumb: "#b4b4b4", + hover: "#808080" + }, P8PAction: { active: "#0000008a" }, @@ -68,5 +73,12 @@ export const P8P_PALETTE = { main: "#1976d2", hover: "#c3e1ff" }, + P8PHeader: { + text: "#37474F", + textLink: "#0F71BD", + link: "#005EA6", + border: "#AFB9CB", + background: "#F5F7F7" + }, P8PPurple: "#5e35b1" }; diff --git a/app/theme/p8p_typography.js b/app/theme/p8p_typography.js index 5651507..18c73fb 100644 --- a/app/theme/p8p_typography.js +++ b/app/theme/p8p_typography.js @@ -176,6 +176,13 @@ export const P8P_TYPOGRAPHY = { lineHeight: "140%", letterSpacing: "0.1px" }, + P8PHeader: { + ...P8PFontMontserrat, + fontWeight: "600", + fontSize: "15px", + lineHeight: "140%", + letterSpacing: "-0.02em" + }, P8PDesktopGroup: { fontFamily: "tahoma, arial, verdana, sans-serif!important", fontSize: "13px !important", @@ -212,6 +219,7 @@ export const P8P_TYPOGRAPHY_VARIANT = { INPUT_LABEL: "P8PInputLabel", BODY2_BOLD: "P8PBody2Bold", TITLE: "P8PTitle", + HEADER: "P8PHeader", DESKTOP_GROUP: "P8PDesktopGroup", DESKTOP_CAPTION: "P8PDesktopCaption" }; diff --git a/app/theme/styles/box.js b/app/theme/styles/box.js index 5fa3a27..4a9b09d 100644 --- a/app/theme/styles/box.js +++ b/app/theme/styles/box.js @@ -7,7 +7,8 @@ //Подключение библиотек //--------------------- -import { P8P_COMPONENT_WIDTH, P8P_COMPONENT_HEIGHT, P8P_SCROLL_AUTO } from "./common"; //Стили - общие +import { hasValue } from "../../core/utils"; +import { P8P_SCROLL_AUTO } from "./common"; //Стили - общие import { useTheme } from "@mui/material/styles"; //Хук темы приложения //--------- @@ -41,21 +42,40 @@ export const P8P_BOX_CENTER_BETWEEN = { //Контейнер плавающий, элементы по центру export const P8P_BOX_CENTER = { display: "flex", alignItems: "center", justifyContent: "center" }; +//Контейнер с возможностью нажатия +export const P8P_BOX_CLICKABLE = { + cursor: "pointer", + "&:hover": { + opacity: 0.8 + } +}; + +//Контейнер для заголовка диалога +export const P8P_BOX_DIALOG_TITLE = { + display: "grid", + gridTemplateColumns: "1fr auto 1fr", + alignItems: "center", + gap: "16px" +}; + //--------- //Стили приложения //--------- //Контейнер рабочего пространства export const P8P_BOX_APP_WORKSPACE = { - ...P8P_COMPONENT_WIDTH({ width: "100vw" }), - //width: "100vw", - ...P8P_BOX_CENTER_BETWEEN + width: "100vw", + display: "flex", + alignItems: "center", + justifyContent: "space-between" }; //Меню панелей - контейнер грида export const P8P_BOX_PANELS_MENU_CONTAINER = { - ...P8P_BOX_CENTER_START, - ...P8P_COMPONENT_HEIGHT({ minHeight: "100vh" }) + minHeight: "100vh", + display: "flex", + alignItems: "center", + justifyContent: "flex-start" }; //--------- @@ -64,16 +84,16 @@ export const P8P_BOX_PANELS_MENU_CONTAINER = { //Список настроек панели export const P8P_BOX_SETTINGS_LIST = { - ...P8P_COMPONENT_WIDTH({ width: "520px" }), - ...P8P_COMPONENT_HEIGHT({ height: "500px" }), - ...P8P_SCROLL_AUTO + ...P8P_SCROLL_AUTO, + width: "520px", + height: "500px" }; //Список панелей настроек панелей export const P8P_BOX_SETTINGS_PANELS = { - ...P8P_COMPONENT_WIDTH({ width: "300px" }), - ...P8P_COMPONENT_HEIGHT({ height: "500px" }), - ...P8P_SCROLL_AUTO + ...P8P_SCROLL_AUTO, + width: "300px", + height: "500px" }; //Контейнер настроек панелей @@ -89,8 +109,7 @@ export const P8P_BOX_SETTINGS_CONTAINER = { //Контейнер диаграмы Ганта export const P8P_BOX_GANTT = ({ noData, zoomBarHeight, titleHeight }) => ({ - ...P8P_COMPONENT_HEIGHT({ height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})` }), - //height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})`, + height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})`, display: noData ? "none" : "" }); @@ -100,11 +119,10 @@ export const P8P_BOX_GANTT = ({ noData, zoomBarHeight, titleHeight }) => ({ //Контейнер циклограммы export const P8P_BOX_CYCLOGRAM = ({ noData, zoomBarHeight, titleHeight }) => ({ + height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})`, position: "relative", overflow: "auto", padding: "0px 8px", - ...P8P_COMPONENT_HEIGHT({ height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})` }), - //height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})`, display: noData ? "none" : "" }); @@ -124,9 +142,11 @@ export const P8P_BOX_CYCLOGRAM_GROUP = ({ height }) => { const theme = useTheme(); //Возвращаем стиль return { + display: "flex", + alignItems: "center", + justifyContent: "center", border: "1px solid", backgroundColor: theme.palette.P8PCyclogram.group, - ...P8P_BOX_CENTER, height }; }; @@ -150,3 +170,67 @@ export const P8P_BOX_CYCLOGRAM_TASK = ({ lineHeight, bgColor, textColor, highlig } }; }; + +//--------- +//Стили заголовка +//--------- + +//Контейнер заголовка +export const P8P_BOX_HEADER = ({ isFixed }) => ({ + display: "flex", + flexDirection: "row", + alignItems: "flex-start", + padding: "0px", + width: "100vw", + height: "64px", + background: "P8PHeader.background", + boxShadow: "0px 6px 6px rgba(182, 189, 201, 0.17), 0px 1px 3px rgba(182, 189, 201, 0.2)", + position: isFixed ? "fixed" : "relative", + overflow: "hidden" +}); + +//Контейнер элемента заголовка +export const P8P_BOX_HEADER_ITEM = ({ width, minWidth, isClickable }) => ({ + height: "100%", + width, + minWidth, + display: "flex", + alignItems: "center", + justifyContent: "center", + flexDirection: "column", + borderRight: "1px solid", + borderColor: "P8PHeader.border", + ...(!hasValue(width) ? { flex: 1 } : {}), + ...(isClickable ? { ...P8P_BOX_CLICKABLE } : {}) +}); + +//Контейнер фильтров +export const P8P_BOX_HEADER_FILTER = ({ width, isLimited, isLessMinWidth }) => ({ + ...P8P_BOX_HEADER_ITEM({ width }), + minWidth: isLimited ? "max-content" : isLessMinWidth ? "73px" : null, + display: "flex", + alignItems: "center", + justifyContent: "flex-start", + flexDirection: "row", + overflow: "hidden", + padding: "0px 16px" +}); + +//Контейнер списка фильтров +export const P8P_BOX_HEADER_FILTER_GRP = { + minWidth: "0px", + height: "100%", + alignContent: "center", + flex: "1 1 0", + whiteSpace: "nowrap", + textOverflow: "ellipsis" +}; + +//Контейнер для кастомного фильтра +export const P8P_BOX_HEADER_FILTER_CUSTOM = { + display: "-webkit-box", + overflow: "hidden", + WebkitBoxOrient: "vertical", + WebkitLineClamp: 1, + color: "P8PText.primary" +}; diff --git a/app/theme/styles/common.js b/app/theme/styles/common.js index 475aa84..f1b5b34 100644 --- a/app/theme/styles/common.js +++ b/app/theme/styles/common.js @@ -3,12 +3,6 @@ Вспомогательные стили - общие */ -//--------------------- -//Подключение библиотек -//--------------------- - -import { APP_STYLES } from "../../../app.styles"; //Типовые стили - //---------------- //Интерфейс модуля //---------------- @@ -27,10 +21,10 @@ export const P8P_COMPONENT_HEIGHT = ({ height, minHeight, maxHeight }) => ({ ...(maxHeight ? { maxHeight } : {}) }); -//Отображаемый скролл -export const P8P_SCROLL_AUTO = { - overflow: "auto", - ...APP_STYLES.SCROLL +//Полная ширина и высота +export const P8P_COMPONENT_FULL_SIZE = { + height: "100%", + width: "100%" }; //Отсутствие отступов @@ -38,6 +32,12 @@ export const P8P_COMPONENT_ZERO_PADDING = { padding: "0px" }; +//Блок с возможностью нажатия +export const P8P_COMPONENT_CLICKABLE_OPACITY = { + cursor: "pointer", + "&:hover": { backgroundColor: "inherit", opacity: "0.8" } +}; + //Стили export const P8P_SCROLL = { "&::-webkit-scrollbar": { @@ -46,13 +46,19 @@ export const P8P_SCROLL = { }, "&::-webkit-scrollbar-track": { borderRadius: "8px", - backgroundColor: "#EBEBEB" + backgroundColor: "P8PScroll.track" }, "&::-webkit-scrollbar-thumb": { borderRadius: "8px", - backgroundColor: "#b4b4b4" + backgroundColor: "P8PScroll.thumb" }, "&::-webkit-scrollbar-thumb:hover": { - backgroundColor: "#808080" + backgroundColor: "P8PScroll.hover" } }; + +//Отображаемый скролл +export const P8P_SCROLL_AUTO = { + overflow: "auto", + ...P8P_SCROLL +}; diff --git a/app/theme/styles/form_control.js b/app/theme/styles/form_control.js new file mode 100644 index 0000000..c770b0f --- /dev/null +++ b/app/theme/styles/form_control.js @@ -0,0 +1,30 @@ +/* + Парус 8 - Панели мониторинга + Вспомогательные стили FormControl +*/ + +//---------------- +//Интерфейс модуля +//---------------- + +//--------- +//Стили заголовка +//--------- + +//Поле ввода заголовка +export const P8P_FORM_CONTROL_HEADER_FIELD = { + height: "100%", + width: "100%", + display: "flex", + alignItems: "center", + justifyContent: "center", + margin: "0px", + padding: "0px 16px" +}; + +//Поле выбора заголовка +export const P8P_FORM_CONTROL_HEADER_SELECTOR = { + height: "100%", + width: "100%", + padding: "0px 8px" +}; diff --git a/app/theme/styles/grid.js b/app/theme/styles/grid.js new file mode 100644 index 0000000..47e88df --- /dev/null +++ b/app/theme/styles/grid.js @@ -0,0 +1,19 @@ +/* + Парус 8 - Панели мониторинга + Вспомогательные стили Grid +*/ + +//---------------- +//Интерфейс модуля +//---------------- + +//--------- +//Стили заголовка +//--------- + +//Элемент списка фильтров заголовка +export const P8P_GRID_HEADER_FILTER_ITEM = ({ width, isLimited, isLessMinWidth }) => ({ + width: width || "auto", + flexShrink: isLimited ? 0 : 1, + visibility: isLessMinWidth ? "hidden" : "visible" +}); diff --git a/app/theme/styles/paper.js b/app/theme/styles/paper.js index 223350c..b4a19bb 100644 --- a/app/theme/styles/paper.js +++ b/app/theme/styles/paper.js @@ -10,7 +10,6 @@ import { useTheme } from "@mui/material/styles"; //Хук темы приложения import { STATE } from "../../../app.text"; //Типовые текстовые ресурсы и константы import { P8P_COLOR_STATE, P8P_COLOR_STATE_BG } from "../colors/common"; //Дополнительные цвета - общие -import { P8P_COMPONENT_WIDTH, P8P_COMPONENT_HEIGHT } from "./common"; //Стили - общие //--------- //Константы @@ -44,11 +43,9 @@ export const P8P_PAPER_INDICATOR = ({ state, color, backgroundColor, clickable } const theme = useTheme(); //Возвращаем стиль return { + height: "100%", + width: "100%", padding: "10px", - ...P8P_COMPONENT_WIDTH({ width: "100%" }), - ...P8P_COMPONENT_HEIGHT({ height: "100%" }), - //width: "100%", - //height: "100%", overflow: "hidden", backgroundColor: backgroundColor || P8P_INDICATOR_BG_COLOR[state], color: color || P8P_INDICATOR_COLOR[state], diff --git a/app/theme/styles/stack.js b/app/theme/styles/stack.js index 1fb2f8f..1845402 100644 --- a/app/theme/styles/stack.js +++ b/app/theme/styles/stack.js @@ -3,11 +3,7 @@ Вспомогательные стили Stack */ -//--------------------- -//Подключение библиотек -//--------------------- - -import { P8P_COMPONENT_WIDTH } from "./common"; //Стили - общие +import { P8P_COMPONENT_CLICKABLE_OPACITY } from "./common"; //---------------- //Интерфейс модуля @@ -15,8 +11,68 @@ import { P8P_COMPONENT_WIDTH } from "./common"; //Стили - общие //Адаптивный с сокрытием export const P8P_STACK_INLINE_HIDDEN = { - ...P8P_COMPONENT_WIDTH({ width: "100%" }), + width: "100%", containerType: "inline-size", - //width: "100%", overflow: "hidden" }; + +//--------- +//Стили заголовка +//--------- + +//Контейнер текста заголовка +export const P8P_STACK_HEADER_TEXT = ({ isClickable }) => ({ + height: "100%", + width: "100%", + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "0px 8px", + color: isClickable ? "P8PHeader.textLink" : "P8PHeader.text", + ...(isClickable ? { ...P8P_COMPONENT_CLICKABLE_OPACITY } : {}) +}); + +//Контейнер фильтра заголовка +export const P8P_STACK_HEADER_FILTER = ({ isClickable = false }) => ({ + width: "100%", + display: "flex", + flexDirection: "column", + alignItems: "flex-start", + alignContent: "flex-start", + cursor: isClickable ? "pointer" : "default", + overflow: "hidden" +}); + +//Контейнер фильтра заголовка +export const P8P_STACK_HEADER_FILTER_CONTAINER = ({ isClickable = false }) => ({ + height: "100%", + width: "100%", + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "4px", + paddingRight: "4px", + "&:hover": isClickable ? { opacity: 0.8 } : {} +}); + +//Контейнер кнопки с очисткой +export const P8P_STACK_HEADER_WITH_CLEAR = { + height: "100%", + width: "100%", + display: "flex", + flexDirection: "row", + alignItems: "center" +}; + +//Контейнер значений индикатора +export const P8P_STACK_HEADER_INDICATOR = ({ isClickable }) => ({ + height: "100%", + width: "100%", + display: "flex", + flexDirection: "column", + alignItems: "start", + justifyContent: "center", + padding: "0px 8px", + overflow: "hidden", + ...(isClickable ? { ...P8P_COMPONENT_CLICKABLE_OPACITY } : {}) +}); diff --git a/app/theme/styles/typography.js b/app/theme/styles/typography.js index 4ed4e9a..8ee50ed 100644 --- a/app/theme/styles/typography.js +++ b/app/theme/styles/typography.js @@ -7,7 +7,20 @@ //Подключение библиотек //--------------------- -import { P8P_COMPONENT_WIDTH, P8P_COMPONENT_HEIGHT } from "./common"; //Стили - общие +import { P8P_COLOR_STATE } from "../colors/common"; //Дополнительные цвета - общие +import { STATE } from "../../../app.text"; //Типовые текстовые ресурсы и константы + +//--------- +//Константы +//--------- + +//Цвета текста индикатора заголовка +const P8P_HEADER_INDICATOR_COLOR = { + [STATE.OK]: P8P_COLOR_STATE[STATE.OK], + [STATE.ERR]: P8P_COLOR_STATE[STATE.ERR], + [STATE.WARN]: P8P_COLOR_STATE[STATE.WARN], + DEFAULT: "P8PHeader.text" +}; //---------------- //Интерфейс модуля @@ -30,8 +43,25 @@ export const P8P_TYPOGRAPHY_DIALOG_TITLE = { //Заголовок export const P8P_TYPOGRAPHY_TITLE = { - ...P8P_COMPONENT_HEIGHT({ height: "44px" }) - //height: "44px" + height: "44px" +}; + +//Максимальное количество строк +export const P8P_TYPOGRAPHY_MAX_LINES = ({ maxLines }) => ({ + width: "100%", + whiteSpace: "wrap", + display: "-webkit-box", + overflow: "hidden", + WebkitBoxOrient: "vertical", + WebkitLineClamp: maxLines +}); + +//Сокрытие лишнего текста +export const P8P_TYPOGRAPHY_HIDDEN = { + textTransform: "none", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap" }; //--------- @@ -40,12 +70,11 @@ export const P8P_TYPOGRAPHY_TITLE = { //Описание панели на рабочем столе export const P8P_TYPOGRAPHY_PANEL_DESK = { + maxWidth: "140px", display: "-webkit-box", overflow: "hidden", WebkitBoxOrient: "vertical", - WebkitLineClamp: 2, - ...P8P_COMPONENT_WIDTH({ maxWidth: "140px" }) - //maxWidth: "140px" + WebkitLineClamp: 2 }; //--------- @@ -72,9 +101,8 @@ export const P8P_TYPOGRAPHY_CG_GROUP = ({ maxWidth, maxHeight }) => ({ //Задача циклограммы export const P8P_TYPOGRAPHY_CG_TASK = ({ maxHeight, availableLines }) => ({ + width: "100%", maxHeight, - ...P8P_COMPONENT_WIDTH({ width: "100%" }), - //width: "100%", padding: "0px 5px", overflowWrap: "break-word", wordBreak: "break-all", @@ -84,3 +112,17 @@ export const P8P_TYPOGRAPHY_CG_TASK = ({ maxHeight, availableLines }) => ({ WebkitBoxOrient: "vertical", WebkitLineClamp: availableLines < 1 ? 1 : availableLines }); + +//--------- +//Стили заголовка +//--------- + +//Индикатор заголовка +export const P8P_TYPOGRAPY_HDR_INDICATOR = ({ maxLines, state, isDefaultColor = false, color }) => ({ + ...P8P_TYPOGRAPHY_MAX_LINES({ maxLines }), + color: isDefaultColor + ? P8P_HEADER_INDICATOR_COLOR.DEFAULT + : color + ? color + : P8P_HEADER_INDICATOR_COLOR[state] || P8P_HEADER_INDICATOR_COLOR.DEFAULT +}); diff --git a/app/theme/utils.js b/app/theme/utils.js index 25dbebe..b6d32bc 100644 --- a/app/theme/utils.js +++ b/app/theme/utils.js @@ -19,7 +19,7 @@ export const getButtonColorStyles = (color, theme, isOutlined = false) => { //Возвращаем результат return { backgroundColor: !isOutlined ? colorObj.main : null, - color: !isOutlined ? colorObj.contrastText || "#FFF" : colorObj.main, + color: !isOutlined ? colorObj.contrastText || theme.palette.P8PBackground.primary : colorObj.main, ...(isOutlined ? { border: `1px solid ${colorObj.main}` } : {}), "&:hover": { textDecoration: "none", diff --git a/app/theme/variants/p8p_button_variants.js b/app/theme/variants/p8p_button_variants.js index 809b471..fe28b49 100644 --- a/app/theme/variants/p8p_button_variants.js +++ b/app/theme/variants/p8p_button_variants.js @@ -7,24 +7,31 @@ //Подключение библиотек //--------------------- +import { P8P_COMPONENT_SIZE } from "../constants"; //Общие константы стилей import { getButtonColorStyles } from "../utils"; //Дополнительные функции стилизации -import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие //--------- //Константы //--------- +//Отступы кнопки заголовка +const P8P_BUTTON_HDR_SIZE = { + [P8P_COMPONENT_SIZE.SMALL]: "0px 8px", + [P8P_COMPONENT_SIZE.MEDIUM]: "0px 16px", + [P8P_COMPONENT_SIZE.LARGE]: "0px 24px" +}; + //Размеры кнопок const P8P_BUTTON_SIZE = { - small: { + [P8P_COMPONENT_SIZE.SMALL]: { fontSize: "13px", padding: "4px 22px" }, - medium: { + [P8P_COMPONENT_SIZE.MEDIUM]: { fontSize: "14px", padding: "6px 22px" }, - large: { + [P8P_COMPONENT_SIZE.LARGE]: { fontSize: "15px", padding: "8px 22px" }, @@ -66,16 +73,27 @@ export const P8P_BUTTONS = ({ theme, color, size }) => ({ border: "none" }, P8PDesktopPanel: { + width: "150px", + height: "90px", fontSize: "12px", textTransform: "none", - ...P8P_COMPONENT_WIDTH({ width: "150px" }), - ...P8P_COMPONENT_HEIGHT({ width: "90px" }), - // width: "150px", - // height: "90px", flexDirection: "column", justifyContent: "flex-start", color: theme.palette.P8PDesktop.main, "&:hover": { backgroundColor: theme.palette.P8PDesktop.hover } + }, + P8PHeader: { + height: "100%", + width: "100%", + borderRadius: "0px", + borderColor: theme.palette.P8PHeader.border, + boxShadow: "none", + textTransform: "none", + color: theme.palette.P8PHeader.link, + backgroundColor: "transparent", + padding: P8P_BUTTON_HDR_SIZE[size] || P8P_BUTTON_HDR_SIZE[P8P_COMPONENT_SIZE.LARGE], + overflow: "hidden", + "&:hover": { backgroundColor: "inherit", opacity: "0.8" } } }); @@ -85,7 +103,8 @@ export const P8P_BUTTON_VARIANT = { SECONDARY: "P8PSecondary", OUTLINED: "P8POutlined", TEXT: "P8PText", - DESKTOP_PANEL: "P8PDesktopPanel" + DESKTOP_PANEL: "P8PDesktopPanel", + HEADER: "P8PHeader" }; //Кастомная стилистика компонента diff --git a/app/theme/variants/p8p_card_variants.js b/app/theme/variants/p8p_card_variants.js index a06aa23..6c9e083 100644 --- a/app/theme/variants/p8p_card_variants.js +++ b/app/theme/variants/p8p_card_variants.js @@ -3,12 +3,6 @@ Расширение стилистики Card */ -//--------------------- -//Подключение библиотек -//--------------------- - -import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие - //---------------- //Интерфейс модуля //---------------- @@ -17,10 +11,8 @@ import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; // export const P8P_CARDS = { primary: {}, P8PPanelInfo: { - ...P8P_COMPONENT_WIDTH({ maxWidth: 400 }), - ...P8P_COMPONENT_HEIGHT({ height: "100%" }), - //maxWidth: 400, - //height: "100%", + maxWidth: "400px", + height: "100%", flexDirection: "column", display: "flex" } diff --git a/app/theme/variants/p8p_container_variants.js b/app/theme/variants/p8p_container_variants.js index af17825..bf378d2 100644 --- a/app/theme/variants/p8p_container_variants.js +++ b/app/theme/variants/p8p_container_variants.js @@ -3,12 +3,6 @@ Расширение стилистики Container */ -//--------------------- -//Подключение библиотек -//--------------------- - -import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие - //---------------- //Интерфейс модуля //---------------- @@ -17,14 +11,12 @@ import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общи export const P8P_CONTAINERS = { primary: {}, P8PTableMoreButton: { - ...P8P_COMPONENT_WIDTH({ width: "100%" }), - //width: "100%", + width: "100%", textAlign: "center", padding: "5px" }, P8PInlineMessage: { - ...P8P_COMPONENT_WIDTH({ width: "100%" }), - //width: "100%", + width: "100%", textAlign: "center" } }; diff --git a/app/theme/variants/p8p_dialog_actions_variants.js b/app/theme/variants/p8p_dialog_actions_variants.js new file mode 100644 index 0000000..38b08f5 --- /dev/null +++ b/app/theme/variants/p8p_dialog_actions_variants.js @@ -0,0 +1,31 @@ +/* + Парус 8 - Панели мониторинга + Расширение стилистики DialogActions +*/ + +//---------------- +//Интерфейс модуля +//---------------- + +//Кастомные диалоги (действия) +export const P8P_DIALOG_ACTIONS = { + primary: {}, + P8PDialog: { padding: "8px 24px 16px 24px" } +}; + +//Наименование кастомных диалогов (действия) +export const P8P_DIALOG_ACTIONS_VARIANT = { + DIALOG: "P8PDialog" +}; + +//Кастомная стилистика компонента +export const P8P_DIALOG_ACTIONS_OVERRIDES = { + styleOverrides: { + root: ({ ownerState }) => { + //Определяем вариант + const variant = ownerState["variant"] || "primary"; + //Возвращаем стили варианта + return P8P_DIALOG_ACTIONS[variant]; + } + } +}; diff --git a/app/theme/variants/p8p_dialog_content_variants.js b/app/theme/variants/p8p_dialog_content_variants.js index 2e04b53..9cf6425 100644 --- a/app/theme/variants/p8p_dialog_content_variants.js +++ b/app/theme/variants/p8p_dialog_content_variants.js @@ -7,24 +7,39 @@ //Подключение библиотек //--------------------- -import { APP_STYLES } from "../../../app.styles"; //Типовые стили -import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие +import { P8P_SCROLL, P8P_SCROLL_AUTO } from "../styles/common"; //Стили - общие + +//--------- +//Константы +//--------- + +//Общие стили +const defaultStyles = paddingDisabled => ({ + ...(paddingDisabled ? { padding: "0px" } : {}) +}); //---------------- //Интерфейс модуля //---------------- //Кастомные диалоги (содержимое) -export const P8P_DIALOG_CONTENTS = theme => ({ +export const P8P_DIALOG_CONTENTS = (theme, paddingDisabled) => ({ primary: {}, - P8PPrimary: { overflow: "auto", ...APP_STYLES.SCROLL }, + P8PPrimary: { ...theme.typography.P8PBody3, ...P8P_SCROLL_AUTO, ...defaultStyles(paddingDisabled) }, P8PTask: { - ...P8P_COMPONENT_WIDTH({ minWidth: 400 }), - //minWidth: 400, - overflowX: "auto" + minWidth: "400px", + overflowX: "auto", + ...P8P_SCROLL, + ...defaultStyles(paddingDisabled) }, - P8PHint: { ...theme.typography.P8PBody4, color: theme.palette.P8PText.primary }, - P8PHidden: { display: "flex", flexDirection: "column", overflow: "hidden" } + P8PHint: { ...theme.typography.P8PBody4, color: theme.palette.P8PText.primary, ...defaultStyles(paddingDisabled) }, + P8PHidden: { + ...theme.typography.P8PBody3, + display: "flex", + flexDirection: "column", + overflow: "hidden", + ...defaultStyles(paddingDisabled) + } }); //Наименование кастомных диалогов (содержимое) @@ -41,8 +56,10 @@ export const P8P_DIALOG_CONTENT_OVERRIDES = { root: ({ ownerState, theme }) => { //Определяем вариант const variant = ownerState["variant"] || "primary"; + //Определяем доп. параметры + const { paddingDisabled } = ownerState["data-variant-props"] || {}; //Возвращаем стили варианта - return P8P_DIALOG_CONTENTS(theme)[variant]; + return P8P_DIALOG_CONTENTS(theme, paddingDisabled)[variant]; } } }; diff --git a/app/theme/variants/p8p_dialog_title_variants.js b/app/theme/variants/p8p_dialog_title_variants.js index 8aaecd1..2cf532b 100644 --- a/app/theme/variants/p8p_dialog_title_variants.js +++ b/app/theme/variants/p8p_dialog_title_variants.js @@ -10,10 +10,11 @@ //Кастомные диалоги (заголовок) export const P8P_DIALOG_TITLES = theme => ({ primary: {}, - P8PPrimary: { ...theme.typography.P8PH6, color: theme.palette.P8PText.primary }, - P8PInfo: { ...theme.typography.P8PH6, color: theme.palette.P8PText.primary }, + P8PPrimary: { ...theme.typography.P8PH6, color: theme.palette.P8PSecondary.main }, + P8PInfo: { ...theme.typography.P8PH6, color: theme.palette.P8PSecondary.main }, P8PWarn: { ...theme.typography.P8PH6, color: theme.palette.P8PWarning.main }, - P8PError: { ...theme.typography.P8PH6, color: theme.palette.P8PError.main } + P8PError: { ...theme.typography.P8PH6, color: theme.palette.P8PError.main }, + P8PPrimaryDivided: { ...theme.typography.P8PH6, color: theme.palette.P8PSecondary.main, borderBottom: "1px solid rgba(42, 48, 57, 0.12)" } }); //Наименование кастомных диалогов (заголовок) @@ -21,7 +22,8 @@ export const P8P_DIALOG_TITLE_VARIANT = { PRIMARY: "P8PPrimary", INFO: "P8PInfo", WARN: "P8PWarn", - ERROR: "P8PError" + ERROR: "P8PError", + PRIMARY_DIVIDED: "P8PPrimaryDivided" }; //Кастомная стилистика компонента diff --git a/app/theme/variants/p8p_drawer_variants.js b/app/theme/variants/p8p_drawer_variants.js index 4c88009..36063a4 100644 --- a/app/theme/variants/p8p_drawer_variants.js +++ b/app/theme/variants/p8p_drawer_variants.js @@ -7,7 +7,7 @@ //Подключение библиотек //--------------------- -import { APP_STYLES } from "../../../app.styles"; //Типовые стили +import { P8P_SCROLL } from "../styles/common"; //Стили - общие //---------------- //Интерфейс модуля @@ -16,7 +16,11 @@ import { APP_STYLES } from "../../../app.styles"; //Типовые стили //Кастомные выезжающие области export const P8P_DRAWERS = { primary: {}, - P8PPrimary: { [`& .MuiDrawer-paper`]: { ...APP_STYLES.SCROLL } } + P8PPrimary: { + [`& .MuiDrawer-paper`]: { + ...P8P_SCROLL + } + } }; //Наименование кастомных выезжающих областей diff --git a/app/theme/variants/p8p_fab_variants.js b/app/theme/variants/p8p_fab_variants.js new file mode 100644 index 0000000..2771db4 --- /dev/null +++ b/app/theme/variants/p8p_fab_variants.js @@ -0,0 +1,42 @@ +/* + Парус 8 - Панели мониторинга + Расширение стилистики Fab +*/ + +//---------------- +//Интерфейс модуля +//---------------- + +//Кастомные плавающие кнопки действия +export const P8P_FABS = theme => ({ + primary: {}, + P8PHeader: { + height: "100%", + width: "100%", + borderRadius: "0px", + borderColor: theme.palette.P8PHeader.border, + backgroundColor: "transparent", + boxShadow: "none", + textTransform: "none", + color: theme.palette.P8PHeader.link, + overflow: "hidden", + "&:hover": { backgroundColor: "inherit", opacity: "0.8" } + } +}); + +//Наименование кастомных плавающих кнопок действий +export const P8P_FAB_VARIANT = { + HEADER: "P8PHeader" +}; + +//Кастомная стилистика компонента +export const P8P_FAB_OVERRIDES = { + styleOverrides: { + root: ({ ownerState, theme }) => { + //Определяем вариант + const variant = ownerState["variant"] || "primary"; + //Возвращаем стили варианта + return P8P_FABS(theme)[variant]; + } + } +}; diff --git a/app/theme/variants/p8p_grid_variants.js b/app/theme/variants/p8p_grid_variants.js index b6110c9..bcebf7c 100644 --- a/app/theme/variants/p8p_grid_variants.js +++ b/app/theme/variants/p8p_grid_variants.js @@ -3,12 +3,6 @@ Расширение стилистики Grid */ -//--------------------- -//Подключение библиотек -//--------------------- - -import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие - //---------------- //Интерфейс модуля //---------------- @@ -18,17 +12,30 @@ export const P8P_GRIDS = { primary: {}, P8PPrimary: {}, P8PSvgContainer: { - ...P8P_COMPONENT_WIDTH({ width: "100%" }), - ...P8P_COMPONENT_HEIGHT({ height: "100%" }) - //width: "100%", - //height: "100%" + width: "100%", + height: "100%" }, P8PPanelsMenu: { - ...P8P_COMPONENT_WIDTH({ maxWidth: 1200 }), - //maxWidth: 1200, + maxWidth: "1200px", direction: "row", justifyContent: "left", alignItems: "stretch" + }, + P8PHeaderFilterContainer: { + height: "100%", + display: "flex", + flexDirection: "row", + alignItems: "center", + position: "relative", + marginTop: "0px", + "& .MuiGrid-item": { + paddingTop: "0 !important" + } + }, + P8PHeaderFilterItem: { + minWidth: "125px", + height: "100%", + alignContent: "center" } }; @@ -36,7 +43,9 @@ export const P8P_GRIDS = { export const P8P_GRID_VARIANT = { PRIMARY: "P8PPrimary", SVG_CONTAINER: "P8PSvgContainer", - PANELS_MENU: "P8PPanelsMenu" + PANELS_MENU: "P8PPanelsMenu", + HEADER_FILTER_CONTAINER: "P8PHeaderFilterContainer", + HEADER_FILTER_ITEM: "P8PHeaderFilterItem" }; //Кастомная стилистика компонента diff --git a/app/theme/variants/p8p_icon_button_variants.js b/app/theme/variants/p8p_icon_button_variants.js index 6bcc9ad..57fdbde 100644 --- a/app/theme/variants/p8p_icon_button_variants.js +++ b/app/theme/variants/p8p_icon_button_variants.js @@ -8,26 +8,40 @@ //---------------- //Кастомные кнопки-иконки -export const P8P_ICON_BUTTONS = { +export const P8P_ICON_BUTTONS = ({ theme }) => ({ primary: {}, P8PAppBarButton: { marginRight: "16px" + }, + P8PHeaderFilterMore: { + flexShrink: 0, + width: "40px", + alignContent: "center", + color: theme.palette.P8PHeader.link + }, + P8PDialogClose: { + color: "#005EA6", + border: `1px solid #005EA6`, + padding: "0px", + borderRadius: "0%" } -}; +}); //Наименования кастомных кнопок-иконкок export const P8P_ICON_BUTTON_VARIANT = { - APP_BAR_BUTTON: "P8PAppBarButton" + APP_BAR_BUTTON: "P8PAppBarButton", + HEADER_FILTER_MORE: "P8PHeaderFilterMore", + DIALOG_CLOSE: "P8PDialogClose" }; //Кастомная стилистика компонента export const P8P_ICON_BUTTON_OVERRIDES = { styleOverrides: { - root: ({ ownerState }) => { + root: ({ ownerState, theme }) => { //Определяем вариант const variant = ownerState?.variant || "primary"; //Возвращаем стили варианта - return P8P_ICON_BUTTONS[variant]; + return P8P_ICON_BUTTONS({ theme })[variant]; } } }; diff --git a/app/theme/variants/p8p_icon_variants.js b/app/theme/variants/p8p_icon_variants.js index f69dae4..4e7caa3 100644 --- a/app/theme/variants/p8p_icon_variants.js +++ b/app/theme/variants/p8p_icon_variants.js @@ -3,49 +3,41 @@ Расширение стилистики Icon */ -//--------------------- -//Подключение библиотек -//--------------------- - -import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие - //---------------- //Интерфейс модуля //---------------- //Кастомные иконки -export const P8P_ICONS = { +export const P8P_ICONS = ({ theme }) => ({ primary: {}, - P8PTableColumnMenu: { - marginRight: "10px" - }, - P8PPanelMenuTitle: { - paddingTop: "4px" - }, + P8PTableColumnMenu: { marginRight: "10px" }, + P8PPanelMenuTitle: { paddingTop: "4px" }, P8PDesktopPanel: { - ...P8P_COMPONENT_WIDTH({ width: "48px" }), - ...P8P_COMPONENT_HEIGHT({ height: "48px" }), - // width: "48px", - // height: "48px", + width: "48px", + height: "48px", fontSize: "48px" - } -}; + }, + P8PHeader: { margin: "0px", fontSize: "24px", color: theme.palette.P8PHeader.link }, + P8PHeaderFilterDelete: { fontSize: "22px" } +}); //Наименование кастомных иконок export const P8P_ICON_VARIANT = { TABLE_COLUMN_MENU: "P8PTableColumnMenu", PANEL_MENU_TITLE: "P8PPanelMenuTitle", - DESKTOP_PANEL: "P8PDesktopPanel" + DESKTOP_PANEL: "P8PDesktopPanel", + HEADER: "P8PHeader", + HEADER_FILTER_DELETE: "P8PHeaderFilterDelete" }; //Кастомная стилистика компонента export const P8P_ICON_OVERRIDES = { styleOverrides: { - root: ({ ownerState }) => { + root: ({ ownerState, theme }) => { //Определяем вариант const variant = ownerState?.variant || "primary"; //Возвращаем стили варианта - return P8P_ICONS[variant]; + return P8P_ICONS({ theme })[variant]; } } }; diff --git a/app/theme/variants/p8p_list_item_variants.js b/app/theme/variants/p8p_list_item_variants.js new file mode 100644 index 0000000..64fd1d5 --- /dev/null +++ b/app/theme/variants/p8p_list_item_variants.js @@ -0,0 +1,37 @@ +/* + Парус 8 - Панели мониторинга + Расширение стилистики ListItem +*/ + +//---------------- +//Интерфейс модуля +//---------------- + +//Кастомные списки +export const P8P_LIST_ITEMS = { + primary: {}, + P8PHeaderFilterMore: { + flexDirection: "column", + alignItems: "flex-start", + borderBottom: "1px solid", + borderColor: "rgba(0, 0, 0, 0.12)", + "&:last-child": { borderBottom: "none" } + } +}; + +//Наименование кастомных списков +export const P8P_LIST_ITEM_VARIANT = { + HEADER_FILTER_MORE: "P8PHeaderFilterMore" +}; + +//Кастомная стилистика компонента +export const P8P_LIST_ITEM_OVERRIDES = { + styleOverrides: { + root: ({ ownerState }) => { + //Определяем вариант + const variant = ownerState["variant"] || "primary"; + //Возвращаем стили варианта + return P8P_LIST_ITEMS[variant]; + } + } +}; diff --git a/app/theme/variants/p8p_list_variants.js b/app/theme/variants/p8p_list_variants.js index 9cef5a7..bf1a01f 100644 --- a/app/theme/variants/p8p_list_variants.js +++ b/app/theme/variants/p8p_list_variants.js @@ -7,7 +7,7 @@ //Подключение библиотек //--------------------- -import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие +import { P8P_SCROLL_AUTO } from "../styles/common"; //Стили - общие //---------------- //Интерфейс модуля @@ -17,20 +17,28 @@ import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общи export const P8P_LISTS = { primary: {}, P8PGanttTask: { - ...P8P_COMPONENT_WIDTH({ width: "100%", minWidth: 300, maxWidth: 700 }) - //width: "100%", minWidth: 300, maxWidth: 700 + width: "100%", + minWidth: "300px", + maxWidth: "700px" }, P8PSettings: { - ...P8P_COMPONENT_WIDTH({ width: "510px" }), - //width: "510px", + width: "510px", overflowY: "auto" + }, + P8PHeaderFilterMore: { + ...P8P_SCROLL_AUTO, + minWidth: "250px", + maxWidth: "400px", + maxHeight: "60vh", + padding: "8px" } }; //Наименование кастомных списков export const P8P_LIST_VARIANT = { GANTT_TASK: "P8PGanttTask", - SETTINGS: "P8PSettings" + SETTINGS: "P8PSettings", + HEADER_FILTER_MORE: "P8PHeaderFilterMore" }; //Кастомная стилистика компонента diff --git a/app/theme/variants/p8p_menu_item_variants.js b/app/theme/variants/p8p_menu_item_variants.js index c69c273..c6d7ed7 100644 --- a/app/theme/variants/p8p_menu_item_variants.js +++ b/app/theme/variants/p8p_menu_item_variants.js @@ -10,12 +10,14 @@ //Кастомные элементы меню export const P8P_MENU_ITEMS = theme => ({ primary: {}, - P8PPrimary: { ...theme.typography.P8PBody1 } + P8PPrimary: { ...theme.typography.P8PBody1 }, + P8PHeader: { ...theme.typography.P8PHeader, color: theme.palette.P8PHeader.link } }); //Наименование кастомных элементов меню export const P8P_MENU_ITEM_VARIANT = { - PRIMARY: "P8PPrimary" + PRIMARY: "P8PPrimary", + HEADER: "P8PHeader" }; //Кастомная стилистика компонента diff --git a/app/theme/variants/p8p_select_variants.js b/app/theme/variants/p8p_select_variants.js index 9d35712..5eab19d 100644 --- a/app/theme/variants/p8p_select_variants.js +++ b/app/theme/variants/p8p_select_variants.js @@ -17,12 +17,21 @@ export const P8P_SELECTS = theme => ({ } }, "& .MuiSelect-select": { ...theme.typography.P8PBody1 } + }, + P8PHeader: { + ...theme.typography.P8PHeader, + height: "100%", + color: theme.palette.P8PHeader.link, + "& .MuiOutlinedInput-notchedOutline": { + border: "none" + } } }); //Наименование кастомных полей выбора export const P8P_SELECT_VARIANT = { - PRIMARY: "P8PPrimary" + PRIMARY: "P8PPrimary", + HEADER: "P8PHeader" }; //Кастомная стилистика компонента diff --git a/app/theme/variants/p8p_table_head_variants.js b/app/theme/variants/p8p_table_head_variants.js index 15fe169..5aaa71d 100644 --- a/app/theme/variants/p8p_table_head_variants.js +++ b/app/theme/variants/p8p_table_head_variants.js @@ -10,11 +10,7 @@ //Кастомные заголовки таблицы export const P8P_TABLE_HEADS = { primary: {}, - P8PSticky: { - position: "sticky", - top: 0, - zIndex: 1000 - } + P8PSticky: { position: "sticky", top: 0, zIndex: 1000 } }; //Наименование кастомных заголовков таблиц diff --git a/app/theme/variants/p8p_text_field_variants.js b/app/theme/variants/p8p_text_field_variants.js index ee862a0..0b557dd 100644 --- a/app/theme/variants/p8p_text_field_variants.js +++ b/app/theme/variants/p8p_text_field_variants.js @@ -22,6 +22,13 @@ export const P8P_TEXT_FIELDS = theme => ({ "& .MuiInputBase-input": { ...theme.typography.P8PBody1 } + }, + P8PHidden: { + width: "100%", + height: "0px", + opacity: 0, + position: "absolute", + pointerEvents: "none" } }); @@ -33,7 +40,8 @@ export const P8P_TEXT_FIELD_OPTIONS = theme => ({ //Наименование кастомных полей ввода export const P8P_TEXT_FIELD_VARIANT = { - PRIMARY: "P8PPrimary" + PRIMARY: "P8PPrimary", + HIDDEN: "P8PHidden" }; //Кастомная стилистика компонента @@ -48,7 +56,6 @@ export const P8P_TEXT_FIELD_OVERRIDES = { option: ({ ownerState, theme }) => { //Определяем вариант const variant = ownerState["data-variant"] || "primary"; - console.log({ option: P8P_TEXT_FIELD_OPTIONS(theme)[variant] }); //Возвращаем стили варианта return P8P_TEXT_FIELD_OPTIONS(theme)[variant]; }