From 9099fa9bb895addb11ceb6ab0186324e32c470a6 Mon Sep 17 00:00:00 2001 From: Yannis Barlas <yannisbarlas@gmail.com> Date: Thu, 17 Sep 2020 21:36:13 +0300 Subject: [PATCH] theming first pass --- wax-prosemirror-components/package.json | 1 + .../src/components/ToolGroupComponent.js | 1 - .../components/comments/ConnectedComment.js | 2 +- wax-prosemirror-components/src/icons/icons.js | 2 +- .../src/ui/buttons/Dropdown.js | 4 +- .../src/ui/buttons/MenuButton.js | 21 ++--- .../src/ui/comments/CommentItem.js | 10 ++- .../src/ui/comments/DateParser.js | 72 ++++++++++++++++++ .../src/ui/tables/InsertTableTool.js | 11 ++- wax-prosemirror-layouts/package.json | 1 + .../src/layouts/EditorElements.js | 23 +++--- .../src/layouts/EditoriaLayout.js | 76 ++++++------------- .../src/coko-theme/index.js | 26 ++++--- yarn.lock | 16 +++- 14 files changed, 174 insertions(+), 92 deletions(-) create mode 100644 wax-prosemirror-components/src/ui/comments/DateParser.js diff --git a/wax-prosemirror-components/package.json b/wax-prosemirror-components/package.json index b8271eed3..cda67ab42 100644 --- a/wax-prosemirror-components/package.json +++ b/wax-prosemirror-components/package.json @@ -17,6 +17,7 @@ "@fortawesome/free-solid-svg-icons": "^5.12.0", "@fortawesome/react-fontawesome": "^0.0.17", "lodash": "^4.17.4", + "moment": "^2.29.0", "prop-types": "^15.7.2", "prosemirror-model": "1.11.0", "prosemirror-state": "1.3.3", diff --git a/wax-prosemirror-components/src/components/ToolGroupComponent.js b/wax-prosemirror-components/src/components/ToolGroupComponent.js index e1f76123f..8fc6f640b 100644 --- a/wax-prosemirror-components/src/components/ToolGroupComponent.js +++ b/wax-prosemirror-components/src/components/ToolGroupComponent.js @@ -5,7 +5,6 @@ import styled from 'styled-components'; import Dropdown from '../ui/buttons/Dropdown'; const Wrapper = styled.div` - background: #fff; display: inline-flex; align-items: center; padding: 0 4px; diff --git a/wax-prosemirror-components/src/components/comments/ConnectedComment.js b/wax-prosemirror-components/src/components/comments/ConnectedComment.js index dea7c8b56..3a3e4e534 100644 --- a/wax-prosemirror-components/src/components/comments/ConnectedComment.js +++ b/wax-prosemirror-components/src/components/comments/ConnectedComment.js @@ -65,7 +65,7 @@ export default ({ comment, top, commentId, recalculateTops }) => { const obj = { content, displayName: user.username, - timestamp: Math.floor(Date.now() / 300000), + timestamp: Math.floor(Date.now()), }; comment.attrs.conversation.push(obj); diff --git a/wax-prosemirror-components/src/icons/icons.js b/wax-prosemirror-components/src/icons/icons.js index c7f654f19..016facfe0 100644 --- a/wax-prosemirror-components/src/icons/icons.js +++ b/wax-prosemirror-components/src/icons/icons.js @@ -35,7 +35,7 @@ export default { check: <FontAwesomeIcon icon={faCheck} />, times: <FontAwesomeIcon icon={faTimes} />, commentBubble: ({ className }) => ( - <Svg viewBox="0 0 24 24"> + <Svg className={className} viewBox="0 0 24 24"> <path d="M0 0h24v24H0z" fill="none" /> <path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 9h12v2H6V9zm8 5H6v-2h8v2zm4-6H6V6h12v2z" /> </Svg> diff --git a/wax-prosemirror-components/src/ui/buttons/Dropdown.js b/wax-prosemirror-components/src/ui/buttons/Dropdown.js index 617302671..ffd67ef3f 100644 --- a/wax-prosemirror-components/src/ui/buttons/Dropdown.js +++ b/wax-prosemirror-components/src/ui/buttons/Dropdown.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import styled from 'styled-components'; import MenuButton from './MenuButton'; +import { grid } from '@pubsweet/ui-toolkit'; // font size 0 reason: https://stackoverflow.com/a/19212391 const Wrapper = styled.div` @@ -11,9 +12,8 @@ const Wrapper = styled.div` `; const DropWrapper = styled.div` - margin-top: 4px; + margin-top: ${grid(1)}; position: absolute; - z-index: 2; `; const Dropdown = props => { diff --git a/wax-prosemirror-components/src/ui/buttons/MenuButton.js b/wax-prosemirror-components/src/ui/buttons/MenuButton.js index 09feb60c9..7445f6af8 100644 --- a/wax-prosemirror-components/src/ui/buttons/MenuButton.js +++ b/wax-prosemirror-components/src/ui/buttons/MenuButton.js @@ -2,27 +2,26 @@ import React from 'react'; import PropTypes from 'prop-types'; import styled, { css } from 'styled-components'; +import { th, override } from '@pubsweet/ui-toolkit'; + import Icon from './Icon'; const activeStyles = css` - background: gray; - color: white; + background: ${th('colorPrimary')}; + color: ${th('colorTextReverse')}; > svg { - fill: white; + fill: ${th('colorTextReverse')}; } &:hover { - background: gray; + background: ${th('colorPrimary')}; } `; const disabledStyles = css` cursor: not-allowed; - - > svg { - fill: gainsboro; - } + opacity: 0.4; &:hover { background: none; @@ -37,21 +36,25 @@ const Wrapper = styled.button.attrs(props => ({ border: none; border-radius: 2px; cursor: pointer; + font-family: ${th('fontInterface')}; height: 28px; outline: none; padding: 2px; transition: all 0.1s ease-in; + color: ${th('colorText')}; > svg { transition: all 0.1s ease-in; } &:hover { - background: gainsboro; + background: ${th('colorBackgroundHue')}; } ${props => props.active && activeStyles} ${props => props.disabled && disabledStyles} + + ${override('Wax.MenuButton')} `; const StyledIcon = styled(Icon)` diff --git a/wax-prosemirror-components/src/ui/comments/CommentItem.js b/wax-prosemirror-components/src/ui/comments/CommentItem.js index 7772a028e..8a668f4e2 100644 --- a/wax-prosemirror-components/src/ui/comments/CommentItem.js +++ b/wax-prosemirror-components/src/ui/comments/CommentItem.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; -// import { th } from '../_helpers' +import DateParser from './DateParser'; const Wrapper = styled.div``; @@ -32,7 +32,13 @@ const CommentItem = props => { <Wrapper className={className}> <Head> <Name>{displayName}</Name> - <Timestamp>{timestamp}</Timestamp> + <Timestamp> + <DateParser timestamp={timestamp}> + {(timeStamp, timeAgo) => { + return `${timeAgo} ago`; + }} + </DateParser> + </Timestamp> </Head> <Content>{content}</Content> </Wrapper> diff --git a/wax-prosemirror-components/src/ui/comments/DateParser.js b/wax-prosemirror-components/src/ui/comments/DateParser.js new file mode 100644 index 000000000..7bd8716bd --- /dev/null +++ b/wax-prosemirror-components/src/ui/comments/DateParser.js @@ -0,0 +1,72 @@ +import moment from 'moment'; +import propTypes from 'prop-types'; + +const getDuration = timestamp => { + const today = moment(); + const stamp = moment(timestamp); + return moment.duration(today.diff(stamp)); +}; + +// const D = ({ children, timestamp, timeAgo }) => children(timestamp, timeAgo); + +// const DateParser = compose( +// setDisplayName('DateParser'), +// withHandlers({ +// renderTimestamp: ({ +// timestamp, +// dateFormat = 'DD.MM.YYYY', +// humanizeThreshold = 0, +// }) => () => { +// if (!timestamp) return ''; +// const duration = getDuration(timestamp); + +// if (duration.asDays() < humanizeThreshold) { +// return `${duration.humanize()} ago`; +// } +// return moment(timestamp).format(dateFormat); +// }, +// renderTimeAgo: ({ timestamp }) => () => { +// if (!timestamp) return ''; +// const duration = getDuration(timestamp); +// return duration.humanize(); +// }, +// }), +// withProps(({ renderTimestamp, renderTimeAgo }) => ({ +// timeAgo: renderTimeAgo(), +// timestamp: renderTimestamp(), +// })), +// )(D); + +const DateParser = props => { + const { children, timestamp, dateFormat, humanizeThreshold } = props; + + const renderTimeAgo = () => { + if (!timestamp) return ''; + const duration = getDuration(timestamp); + return duration.humanize(); + }; + + const renderTimestamp = () => { + if (!timestamp) return ''; + const duration = getDuration(timestamp); + + if (duration.asDays() < humanizeThreshold) { + return `${duration.humanize()} ago`; + } + return moment(timestamp).format(dateFormat); + }; + + return children(renderTimestamp(), renderTimeAgo()); +}; + +DateParser.propTypes = { + /** The date string. Can be any date parsable by momentjs. */ + timestamp: propTypes.oneOfType([propTypes.string, propTypes.number, Date]) + .isRequired, + /** Format of the rendered date. */ + dateFormat: propTypes.string, + /** Humanize duration threshold */ + humanizeThreshold: propTypes.number, +}; + +export default DateParser; diff --git a/wax-prosemirror-components/src/ui/tables/InsertTableTool.js b/wax-prosemirror-components/src/ui/tables/InsertTableTool.js index 73cc4eb6b..37168ed6d 100644 --- a/wax-prosemirror-components/src/ui/tables/InsertTableTool.js +++ b/wax-prosemirror-components/src/ui/tables/InsertTableTool.js @@ -17,6 +17,7 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; +import { withTheme } from 'styled-components'; const clamp = (min, val, max) => { if (val < min) { @@ -77,19 +78,19 @@ const CELL_SIZE = 16; const MAX_SIZE = 20; const GridCell = props => { - const { x, y, selected } = props; + const { x, y, selected, theme } = props; const style = { left: x + 'px', top: y + 'px', width: CELL_SIZE + 'px', height: CELL_SIZE + 'px', - border: '1px solid gray', + border: `1px solid ${theme.colorBorder}`, boxSizing: 'border-box', position: 'absolute', zIndex: 2, }; - if (selected) style.background = '#E2E2E2'; + if (selected) style.background = theme.colorPrimary; return <div style={style} />; }; @@ -99,6 +100,8 @@ GridCell.propTypes = { selected: PropTypes.bool.isRequired, }; +const ThemedCell = withTheme(GridCell); + const TableGridSizeEditor = props => { let _ex = 0; let _ey = 0; @@ -202,7 +205,7 @@ const TableGridSizeEditor = props => { x += GUTTER_SIZE; const selected = ii < rows && jj < cols; cells.push( - <GridCell + <ThemedCell key={`${String(ii)}-${String(jj)}`} selected={selected} x={x} diff --git a/wax-prosemirror-layouts/package.json b/wax-prosemirror-layouts/package.json index e96e5abf1..62430b10f 100644 --- a/wax-prosemirror-layouts/package.json +++ b/wax-prosemirror-layouts/package.json @@ -13,6 +13,7 @@ "build": "BABEL_ENV=production rollup -c" }, "dependencies": { + "@pubsweet/ui-toolkit": "^2.3.1", "react-panelgroup": "^1.0.10", "styled-components": "^4.2.0", "wax-prosemirror-components": "^0.0.19", diff --git a/wax-prosemirror-layouts/src/layouts/EditorElements.js b/wax-prosemirror-layouts/src/layouts/EditorElements.js index 21a55e398..b830a1842 100644 --- a/wax-prosemirror-layouts/src/layouts/EditorElements.js +++ b/wax-prosemirror-layouts/src/layouts/EditorElements.js @@ -1,27 +1,32 @@ import { css } from 'styled-components'; +import { th } from '@pubsweet/ui-toolkit'; + /* All styles regarding ProseMirror surface and elements */ export default css` .ProseMirror { + background: white; counter-reset: footnote; - font-family: ${props => props.theme.fontReading}; + font-family: ${th('fontWriting')}; + color: ${th('colorText')}; + + p::selection, + p span::selection { + background-color: transparent; + } + &:focus { outline: none; } } .ProseMirror .wax-selection-marker { - background: #0a78ff; + background-color: teal; color: white; } div[contenteditable='false'] { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; pointer-events: none; } @@ -180,9 +185,9 @@ export default css` span.deletion { text-decoration: line-through; - color: red; + color: ${th('colorError')}; footnote { - background: red; + background: ${th('colorError')}; } } diff --git a/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js b/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js index 2fcf38483..e8c87ea4b 100644 --- a/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js +++ b/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js @@ -6,57 +6,29 @@ import { componentPlugin } from 'wax-prosemirror-services'; import { cokoTheme } from 'wax-prosemirror-themes'; import { DocumentHelpers } from 'wax-prosemirror-utilities'; import { WaxContext } from 'wax-prosemirror-core'; + +import { grid, th } from '@pubsweet/ui-toolkit'; import EditorElements from './EditorElements'; const divider = css` .divider { - &:before { - content: 'Notes'; - position: relative; - bottom: 14px; - background: white; - z-index: 999; - color: #a3a3a3; - font-weight: 600; - letter-spacing: 0.15em; - } - &:after { - color: #a3a3a3; - content: '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . ' - '. . . . . . . . . . . . . . . . . . . . '; - float: left; - font-weight: 400; - white-space: nowrap; - width: 0; - position: relative; - bottom: 14px; + > div { + background: ${th('colorBorder')}; + height: ${grid(1)}; + max-height: ${grid(1)}; + + &:hover { + height: ${grid(2)}; + max-height: ${grid(2)}; + } } } `; const Wrapper = styled.div` + background: ${th('colorBackground')}; + font-family: ${th('fontInterface')}; + display: flex; flex-direction: column; @@ -74,18 +46,18 @@ const Main = styled.div` const TopMenu = styled.div` display: flex; - justify-content: center; min-height: 40px; user-select: none; - border-bottom: 2px solid #ecedf1; + border-bottom: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')}; > div:not(:last-child) { - border-right: 1px solid #ecedf1; + border-right: ${th('borderWidth')} ${th('borderStyle')} + ${th('colorFurniture')}; } `; const SideMenu = styled.div` - border-right: 1px solid #ecedf1; + border-right: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')}; min-width: 250px; height: 100%; `; @@ -98,7 +70,6 @@ const WaxSurfaceScroll = styled.div` overflow-y: auto; display: flex; box-sizing: border-box; - padding: 0 2px 2px 2px; height: 100%; width: 100%; @@ -124,22 +95,23 @@ const CommentsContainer = styled.div` `; const NotesAreaContainer = styled.div` + background: ${th('colorBackgroundHue')}; display: flex; flex-direction: row; width: 100%; height: 100%; overflow-y: scroll; - position: absolute; + padding-top: ${grid(1)}; `; const NotesContainer = styled.div` counter-reset: footnote-view; display: flex; flex-direction: column; - padding: 0 0 10px 5px; + padding-left: ${grid(10)}; + padding-bottom: ${grid(4)}; height: 100%; width: 65%; - position: relative; `; let surfaceHeight = 700; @@ -190,8 +162,8 @@ const EditoriaLayout = ({ editor }) => { <PanelGroup direction="column" panelWidths={[ - { size: surfaceHeight, resize: 'stretch' }, - { size: notesHeight, resize: 'stretch' }, + { size: surfaceHeight, resize: 'dynamic' }, + { size: notesHeight, resize: 'dynamic' }, ]} onResizeEnd={onResizeEnd} > diff --git a/wax-prosemirror-themes/src/coko-theme/index.js b/wax-prosemirror-themes/src/coko-theme/index.js index 7f8345715..96d3fe6a0 100644 --- a/wax-prosemirror-themes/src/coko-theme/index.js +++ b/wax-prosemirror-themes/src/coko-theme/index.js @@ -2,18 +2,18 @@ import 'typeface-fira-sans-condensed'; import 'typeface-vollkorn'; -import { ButtonStyles } from './elements'; +import { css } from 'styled-components'; const cokoTheme = { /* Colors */ colorBackground: 'white', - colorPrimary: '#808080', + colorPrimary: 'teal', colorSecondary: '#E7E7E7', colorFurniture: '#CCC', colorBorder: '#AAA', colorBackgroundHue: '#F1F1F1', colorSuccess: '#008800', - colorError: '#FF2D1A', + colorError: 'indianred', colorText: '#111', colorTextReverse: '#FFF', colorTextPlaceholder: '#595959', @@ -24,10 +24,10 @@ const cokoTheme = { /* Text variables */ // fonts - fontInterface: "'Fira Sans Condensed'", - fontHeading: "'Fira Sans Condensed'", - fontReading: "'Vollkorn'", - fontWriting: "'Cokourier Prime Sans'", + fontInterface: 'Fira Sans Condensed', + fontHeading: 'Fira Sans Condensed', + fontReading: 'Vollkorn', + fontWriting: 'Vollkorn', // font sizes fontSizeBase: '16px', @@ -50,7 +50,7 @@ const cokoTheme = { lineHeightHeading6: '24px', /* Spacing */ - gridUnit: '8px', + gridUnit: '4px', /* Border */ borderRadius: '0', @@ -68,8 +68,14 @@ const cokoTheme = { breakpoints: [480, 768, 1000, 1272], cssOverrides: { - ui: { - ButtonStyles, + Wax: { + MenuButton: css` + /* color: magenta; + + > svg { + fill: indianred; + } */ + `, }, }, }; diff --git a/yarn.lock b/yarn.lock index c80c33964..9235c2621 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1979,6 +1979,15 @@ lodash "^4.17.4" styled-components "^4.1.1" +"@pubsweet/ui-toolkit@^2.3.1": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@pubsweet/ui-toolkit/-/ui-toolkit-2.3.2.tgz#44b9b97b399027ef90bf0c30768475284f437fb4" + integrity sha512-VJ9zZI1uDOCicmuJV7uv98kK0J5hGpJKIeXpOSrgPgFw3dDFRjuuLa4W8L5aFa+FG42ZDZEj2CaOnfuZyB4HGA== + dependencies: + color "^3.0.0" + lodash "^4.17.4" + styled-components "^4.1.1" + "@reach/router@^1.3.3": version "1.3.4" resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" @@ -12008,6 +12017,11 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +moment@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.0.tgz#fcbef955844d91deb55438613ddcec56e86a3425" + integrity sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA== + moment@^2.6.0: version "2.27.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" @@ -16755,7 +16769,7 @@ style-to-object@^0.2.1: dependencies: inline-style-parser "0.1.1" -styled-components@4.2.0, styled-components@^4.1.1, styled-components@^4.2.0: +styled-components@^4.1.1, styled-components@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.2.0.tgz#811fbbec4d64c7189f6c7482b9eb6fefa7fefef7" integrity sha512-L/LzkL3ZbBhqIVHdR7DbYujy4tqvTNRfc+4JWDCYyhTatI+8CRRQUmdaR0+ARl03DWsfKLhjewll5uNLrqrl4A== -- GitLab