From 0093804caa7302e94fe4e8e4d499b543facfd91d Mon Sep 17 00:00:00 2001 From: Victor Mutai <victor.mutai@dillieduck.com> Date: Tue, 19 Dec 2023 00:08:16 +0300 Subject: [PATCH] chore: refactor CounterInfoTool --- .../CounterInfoService/CounterInfoTool.js | 5 +- .../CounterInfoService/CounterTool.js | 232 ++++++++++++++++++ 2 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterTool.js diff --git a/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterInfoTool.js b/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterInfoTool.js index d990da40f..7cf10f498 100644 --- a/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterInfoTool.js +++ b/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterInfoTool.js @@ -2,7 +2,8 @@ import React from 'react'; import { isEmpty } from 'lodash'; import { injectable } from 'inversify'; import { Tools } from 'wax-prosemirror-core'; -import EditorInfoTool from './components/EditorInfoTool'; +// import EditorInfoTool from './components/EditorInfoTool'; +import CounterTool from './CounterTool'; @injectable() class CounterInfoTool extends Tools { @@ -22,7 +23,7 @@ class CounterInfoTool extends Tools { renderTool(view) { if (isEmpty(view)) return null; return this.isDisplayed() ? ( - <EditorInfoTool item={this.toJSON()} key="CounterInfo" view={view} /> + <CounterTool item={this.toJSON()} key="CounterInfo" view={view} /> ) : null; } } diff --git a/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterTool.js b/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterTool.js new file mode 100644 index 000000000..396d9bd93 --- /dev/null +++ b/wax-prosemirror-services/src/BottomInfoService/CounterInfoService/CounterTool.js @@ -0,0 +1,232 @@ +import React, { useMemo, useState, useEffect } from 'react'; +import styled from 'styled-components'; +import { grid, override } from '@pubsweet/ui-toolkit'; +import { MenuButton } from 'wax-prosemirror-core'; +import { isEmpty } from 'lodash'; +import { useTranslation } from 'react-i18next'; + +const Wrapper = styled.div` + font-size: 0; + position: relative; + z-index: 2; + + button { + background: ${props => (props.active ? `#535E76` : '#fff')}; + border: ${props => + props.active ? `1px solid #535E76` : `1px solid #D8DAE0`}; + + &:hover { + background: ${props => (props.active ? `#535E76` : '#D8DAE0')}; + } + box-shadow: 0px -2px 6px 1px rgba(204, 204, 204, 0.41); + } + + &:before { + border-bottom: ${props => + props.active ? `8px solid #535E76` : `8px solid #D8DAE0`}; + + border-left: 8px solid transparent; + border-right: 8px solid transparent; + bottom: 26px; + content: ''; + height: 0; + left: 48%; + position: relative; + width: 0; + } + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${override('Wax.CounterWrapper')} +`; + +const DropWrapper = styled.div` + background: white; + margin-top: ${grid(1)}; + position: absolute; + top: 32px; + width: max-content; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${override('Wax.CounterDropWrapper')} +`; + +const CounterInfoComponent = styled.div` + background: #fff; + border-radius: 1.03093% / 8%; + bottom: 45px; + box-shadow: rgb(9 30 66 / 25%) 0px 4px 8px 0px, + rgb(9 30 66 / 31%) 0px 0px 1px 0px; + display: flex; + flex-direction: column; + font-size: 14px; + padding: calc(4px * 2); + position: fixed; + right: 31px; + transform-origin: 50% 50% 0px; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${override('Wax.CounterInfoComponent')} +`; + +const Counter = styled.div` + color: black; + display: block; + font-size: 14px; + height: 25px; + margin: 5px; + min-width: 150px; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${override('Wax.Counters')} +`; + +const CounterTool = ({ view: { state }, item }) => { + const { t, i18n } = useTranslation(); + + const [isOpen, setIsOpen] = useState(true); + + const [wordCount, setWordCount] = useState(0); + const [characterCount, setCharacterCount] = useState(0); + const [charactersNoSpaceCount, setCharactersNoSpace] = useState(0); + const [paragraphCount, setParagraphCount] = useState(0); + const [imageCount, setImageCount] = useState(0); + const [footnoteCount, setFootnoteCount] = useState(0); + const [tableCount, setTableCount] = useState(0); + // eslint-disable-next-line no-unused-vars + const [blockLevelNodes, setBlockLevelNodes] = useState(0); + + useEffect(() => { + const docText = state.doc.textBetween( + 0, + state.doc.content.size, + undefined, + ' ', + ); + + const wordCounter = docText.split(' ').filter(word => word !== '').length; + const chars = docText.split(''); + + const charactersNoSpace = chars.filter(char => char !== ' ').length; + + setWordCount(wordCounter); + setCharacterCount(charactersNoSpace); + setCharactersNoSpace(chars.length); + + state.doc.descendants(node => { + if (node.type.name === 'paragraph') { + setParagraphCount(prevState => prevState + 1); + } + if (node.type.name === 'image') { + setImageCount(prevState => prevState + 1); + } + if (node.type.groups.includes('notes')) { + setFootnoteCount(prevState => prevState + 1); + } + if (node.type.name === 'table') { + setTableCount(prevState => prevState + 1); + } + }); + }, []); + + const infoDropDownOptions = [ + { + name: `${wordCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Words`) + ? t(`Wax.Counters.Words`) + : 'Words' + }`, + }, + { + name: `${characterCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Characters`) + ? t(`Wax.Counters.Characters`) + : 'Characters' + }`, + }, + { + name: `${charactersNoSpaceCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Characters Without Space`) + ? t(`Wax.Counters.Characters Without Space`) + : 'Characters Without Space' + }`, + }, + { + name: `${paragraphCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Paragraph`) + ? t(`Wax.Counters.Paragraph`) + : 'Paragraph' + }`, + }, + { + name: `${imageCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Images`) + ? t(`Wax.Counters.Images`) + : 'Images' + }`, + }, + { + name: `${tableCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Tables`) + ? t(`Wax.Counters.Tables`) + : 'Tables' + }`, + }, + { + name: `${footnoteCount} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Footnotes`) + ? t(`Wax.Counters.Footnotes`) + : 'Footnotes' + }`, + }, + { + name: `${blockLevelNodes} ${ + !isEmpty(i18n) && i18n.exists(`Wax.Counters.Block-Level Nodes`) + ? t(`Wax.Counters.Block-Level Nodes`) + : 'Block-Level Nodes' + }`, + }, + ]; + + const renderList = () => { + const lists = []; + + Object.keys(infoDropDownOptions).forEach(key => { + lists.push( + <Counter key={key} title={infoDropDownOptions[key].name}> + <span>{infoDropDownOptions[key].name}</span> + </Counter>, + ); + }); + return <div>{lists}</div>; + }; + + const MenuButtonComponent = useMemo( + () => ( + <Wrapper active={isOpen}> + <MenuButton + active={isOpen} + disabled={false} + label="Words" + title={item.title} + /> + + {isOpen && ( + <DropWrapper> + <CounterInfoComponent + close={() => setIsOpen(false)} + item={item} + view={state} + > + {renderList()} + </CounterInfoComponent> + </DropWrapper> + )} + </Wrapper> + ), + [isOpen, renderList], + ); + + return MenuButtonComponent; +}; + +export default CounterTool; -- GitLab