From 3d8bedaf2d44df5011b3ae21632b8266c2306986 Mon Sep 17 00:00:00 2001 From: Yannis Barlas <yannisbarlas@gmail.com> Date: Mon, 28 Sep 2020 23:22:54 +0300 Subject: [PATCH] sidebar styles & basic editoria layout --- editors/editoria/src/Editoria.js | 13 +- stories/tabs/BlockElement.stories.js | 2 +- stories/tabs/BlockElementGroup.stories.js | 4 +- wax-prosemirror-components/index.js | 3 + .../src/components/ToolGroupComponent.js | 4 +- wax-prosemirror-components/src/icons/icons.js | 65 +----- .../src/ui/tabs/BlockElement.js | 8 +- .../src/ui/tabs/BlockElementGroup.js | 23 ++- .../src/ui/tabs/BlockLevelTools.js | 13 +- .../src/ui/tabs/Tabs.js | 19 +- wax-prosemirror-core/src/Wax.js | 42 ++-- .../src/layouts/EditoriaLayout.js | 194 +++++++----------- .../DisplayText.js | 45 +++- 13 files changed, 196 insertions(+), 239 deletions(-) diff --git a/editors/editoria/src/Editoria.js b/editors/editoria/src/Editoria.js index ef823aeea..e7b51cea4 100644 --- a/editors/editoria/src/Editoria.js +++ b/editors/editoria/src/Editoria.js @@ -1,5 +1,5 @@ import React, { Fragment } from 'react'; -import styled, { createGlobalStyle } from 'styled-components'; +import { createGlobalStyle } from 'styled-components'; import { EditoriaLayout } from 'wax-prosemirror-layouts'; import { Wax } from 'wax-prosemirror-core'; @@ -12,17 +12,12 @@ const GlobalStyle = createGlobalStyle` margin: 0; padding: 0; overflow-y: hidden; + } + #root { height:100vh; width:100vw; } - } -`; - -const StyledWax = styled(Wax)` - .wax-surface-scroll { - /* height: ${props => (props.debug ? '50vh' : '100%')}; */ - } `; const renderImage = file => { @@ -43,7 +38,7 @@ const user = { const Editoria = () => ( <Fragment> <GlobalStyle /> - <StyledWax + <Wax config={config} autoFocus placeholder="Type Something..." diff --git a/stories/tabs/BlockElement.stories.js b/stories/tabs/BlockElement.stories.js index 831f803db..20a7d444f 100644 --- a/stories/tabs/BlockElement.stories.js +++ b/stories/tabs/BlockElement.stories.js @@ -3,7 +3,7 @@ import React from 'react'; import BlockElement from '../../wax-prosemirror-components/src/ui/tabs/BlockElement'; const item = { - content: 'something', + label: 'something', }; export const Base = () => <BlockElement item={item} isNested={false} />; diff --git a/stories/tabs/BlockElementGroup.stories.js b/stories/tabs/BlockElementGroup.stories.js index 8dce998f1..4074ccc2b 100644 --- a/stories/tabs/BlockElementGroup.stories.js +++ b/stories/tabs/BlockElementGroup.stories.js @@ -4,10 +4,10 @@ import BlockElementGroup from '../../wax-prosemirror-components/src/ui/tabs/Bloc const items = [ { - content: 'Heading 1', + label: 'Heading 1', }, { - content: 'Heading 2', + label: 'Heading 2', }, ]; diff --git a/wax-prosemirror-components/index.js b/wax-prosemirror-components/index.js index 11aab0380..0742df29f 100644 --- a/wax-prosemirror-components/index.js +++ b/wax-prosemirror-components/index.js @@ -19,3 +19,6 @@ export { default as RightArea } from './src/components/rightArea/RightArea'; export { default as TrackChangeEnable } from './src/components/trackChanges/TrackChangeEnable'; export { default as CreateTable } from './src/components/tables/CreateTable'; + +export { default as Tabs } from './src/ui/tabs/Tabs'; +export { default as BlockLevelTools } from './src/ui/tabs/BlockLevelTools'; diff --git a/wax-prosemirror-components/src/components/ToolGroupComponent.js b/wax-prosemirror-components/src/components/ToolGroupComponent.js index fe3d20e36..e1f76123f 100644 --- a/wax-prosemirror-components/src/components/ToolGroupComponent.js +++ b/wax-prosemirror-components/src/components/ToolGroupComponent.js @@ -21,10 +21,9 @@ const DropWrapper = styled(Wrapper)` padding: 4px; `; -const ToolGroupComponent = ({ view, tools, name, title }) => { +const ToolGroupComponent = ({ view, tools, name }) => { const toolsShown = []; const rest = []; - const DisplayTitle = isFunction(title) ? title : () => title; tools.forEach(tool => { tool.isIntoMoreSection() && tool.isDisplayed() @@ -34,7 +33,6 @@ const ToolGroupComponent = ({ view, tools, name, title }) => { return ( <Wrapper data-name={name}> - {/* <DisplayTitle /> */} {toolsShown} {rest.length > 0 && ( <Dropdown diff --git a/wax-prosemirror-components/src/icons/icons.js b/wax-prosemirror-components/src/icons/icons.js index 89e6a6886..c7f654f19 100644 --- a/wax-prosemirror-components/src/icons/icons.js +++ b/wax-prosemirror-components/src/icons/icons.js @@ -6,31 +6,12 @@ import React from 'react'; import styled from 'styled-components'; import FontAwesomeIcon from '@fortawesome/react-fontawesome'; import { - faBold, - faItalic, faCheck, - faCode, - faSuperscript, - faSubscript, - faUnderline, - faStrikethrough, - faLink, faParagraph, faHeading, faQuoteLeft, - faListOl, - faListUl, - faImage, - faTable, faTimes, - faUndo, - faRedo, - faOutdent, - faAngleUp, - faStickyNote, faVial, - faFileCode, - faEllipsisH, } from '@fortawesome/free-solid-svg-icons'; // default values @@ -47,50 +28,10 @@ const Svg = styled.svg.attrs(() => ({ `; export default { - // em: <FontAwesomeIcon icon={faItalic} />, - // italic: <FontAwesomeIcon icon={faItalic} />, - // strong: <FontAwesomeIcon icon={faBold} />, - // bold: <FontAwesomeIcon icon={faBold} />, - // code: <FontAwesomeIcon icon={faCode} />, - // subscript: <FontAwesomeIcon icon={faSubscript} />, - // superscript: <FontAwesomeIcon icon={faSuperscript} />, - // underline: <FontAwesomeIcon icon={faUnderline} />, - // strikethrough: <FontAwesomeIcon icon={faStrikethrough} />, - // link: <FontAwesomeIcon icon={faLink} />, paragraph: <FontAwesomeIcon icon={faParagraph} />, heading: <FontAwesomeIcon icon={faHeading} />, blockquote: <FontAwesomeIcon icon={faQuoteLeft} />, - // code_block: <FontAwesomeIcon icon={faFileCode} />, - // ordered_list: <FontAwesomeIcon icon={faListOl} />, - // bullet_list: <FontAwesomeIcon icon={faListUl} />, - // image: <FontAwesomeIcon icon={faImage} />, - // table: <FontAwesomeIcon icon={faTable} />, - // footnote: <FontAwesomeIcon icon={faStickyNote} />, - // undo: <FontAwesomeIcon icon={faUndo} />, - // redo: <FontAwesomeIcon icon={faRedo} />, - // lift: <FontAwesomeIcon icon={faOutdent} />, - // join_up: <FontAwesomeIcon icon={faAngleUp} />, source: <FontAwesomeIcon icon={faVial} />, - // ellipses: <FontAwesomeIcon icon={faEllipsisH} />, - // small_caps: ( - // <span className="small-caps"> - // <svg - // width="35" - // height="20" - // viewBox="0 0 35 20" - // fill="none" - // xmlns="http://www.w3.org/2000/svg" - // > - // <path - // fillRule="evenodd" - // clipRule="evenodd" - // d="M9.21799 1.12207L9.34998 0H0V1.12207H4.004V15.0701H5.258V1.12207H9.21799ZM14.14 6.34912L14.242 5.51611H7.935V6.34912H10.587V15.0701H11.539V6.34912H14.14Z" - // transform="translate(10.286 8.92993)" - // fill="#4F4F4F" - // /> - // </svg> - // </span> - // ), check: <FontAwesomeIcon icon={faCheck} />, times: <FontAwesomeIcon icon={faTimes} />, commentBubble: ({ className }) => ( @@ -271,4 +212,10 @@ export default { </g> </Svg> ), + title: ({ className }) => ( + <Svg className={className} viewBox="0 0 24 24"> + <path d="M0 0h24v24H0V0z" fill="none" /> + <path d="M5 4v3h5.5v12h3V7H19V4z" /> + </Svg> + ), }; diff --git a/wax-prosemirror-components/src/ui/tabs/BlockElement.js b/wax-prosemirror-components/src/ui/tabs/BlockElement.js index 1ff4cdeec..c8e853035 100644 --- a/wax-prosemirror-components/src/ui/tabs/BlockElement.js +++ b/wax-prosemirror-components/src/ui/tabs/BlockElement.js @@ -14,22 +14,22 @@ const Box = styled.div` background: gray; `; -const Label = styled(Button)``; +const StyledButton = styled(Button)``; const BlockElement = props => { - const { item, onClick } = props; + const { item, onClick, view } = props; return ( <Wrapper onClick={onClick}> <Box /> - <Label item={item} /> + <StyledButton item={item} view={view} /> </Wrapper> ); }; BlockElement.propTypes = { item: PropTypes.shape({ - content: PropTypes.string, + label: PropTypes.string, }).isRequired, }; diff --git a/wax-prosemirror-components/src/ui/tabs/BlockElementGroup.js b/wax-prosemirror-components/src/ui/tabs/BlockElementGroup.js index f04ec8513..9c640c5b5 100644 --- a/wax-prosemirror-components/src/ui/tabs/BlockElementGroup.js +++ b/wax-prosemirror-components/src/ui/tabs/BlockElementGroup.js @@ -4,15 +4,32 @@ import styled from 'styled-components'; import BlockElement from './BlockElement'; const Wrapper = styled.div``; -const GroupName = styled.div``; + +const GroupName = styled.div` + margin-bottom: 4px; + font-size: 14px; + text-transform: uppercase; +`; + +const ListWrapper = styled.div` + > div:not(:last-child) { + margin-bottom: 4px; + } +`; const BlockElementGroup = props => { - const { groupName, items } = props; + const { groupName, items, view } = props; return ( <Wrapper> <GroupName>{groupName}</GroupName> - {items && items.map(item => <BlockElement item={item} />)} + + <ListWrapper> + {items && + items.map(item => ( + <BlockElement key={item.name} item={item} view={view} /> + ))} + </ListWrapper> </Wrapper> ); }; diff --git a/wax-prosemirror-components/src/ui/tabs/BlockLevelTools.js b/wax-prosemirror-components/src/ui/tabs/BlockLevelTools.js index e18efcae6..f52e7b5b8 100644 --- a/wax-prosemirror-components/src/ui/tabs/BlockLevelTools.js +++ b/wax-prosemirror-components/src/ui/tabs/BlockLevelTools.js @@ -5,19 +5,26 @@ import styled from 'styled-components'; import BlockElementGroup from './BlockElementGroup'; const Wrapper = styled.div` + padding: 8px; + > div:not(:last-child) { margin-bottom: 8px; } `; const BlockLevelTools = props => { - const { groups } = props; + const { groups, view } = props; return ( <Wrapper> {groups && groups.map(group => ( - <BlockElementGroup groupName={group.groupName} items={group.items} /> + <BlockElementGroup + groupName={group.groupName} + key={group.groupName} + items={group.items} + view={view} + /> ))} </Wrapper> ); @@ -29,7 +36,7 @@ BlockLevelTools.propTypes = { groupName: PropTypes.string, items: PropTypes.arrayOf( PropTypes.shape({ - content: PropTypes.string, + label: PropTypes.string, }), ), }), diff --git a/wax-prosemirror-components/src/ui/tabs/Tabs.js b/wax-prosemirror-components/src/ui/tabs/Tabs.js index 1d56c32ec..e2751296d 100644 --- a/wax-prosemirror-components/src/ui/tabs/Tabs.js +++ b/wax-prosemirror-components/src/ui/tabs/Tabs.js @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; import styled, { css } from 'styled-components'; +import Icon from '../buttons/Icon'; const Wrapper = styled.div` display: flex; @@ -10,7 +11,6 @@ const Wrapper = styled.div` const Tabs = styled.div` display: flex; flex-direction: column; - margin-right: 10px; `; const activeTab = css` @@ -18,23 +18,26 @@ const activeTab = css` `; const Tab = styled.div` - height: 50px; - width: 50px; - background: papayawhip; - margin-bottom: 5px; + background: gainsboro; + padding: 8px; + margin: 0 4px 4px 4px; cursor: pointer; + &:first-child { + margin-top: 4px; + } + ${props => props.active && activeTab} &:hover { - background: gray; + background: silver; } `; const Content = styled.div` width: 100%; height: 100%; - border: 1px solid gray; + background: gainsboro; `; const TabsPane = props => { @@ -52,7 +55,7 @@ const TabsPane = props => { key={tab.id} onClick={() => setTabDisplay(tab.id)} > - {tab.displayName} + <Icon name={tab.icon} /> </Tab> ))} </Tabs> diff --git a/wax-prosemirror-core/src/Wax.js b/wax-prosemirror-core/src/Wax.js index 0cc74c051..a97c6c3af 100644 --- a/wax-prosemirror-core/src/Wax.js +++ b/wax-prosemirror-core/src/Wax.js @@ -1,7 +1,6 @@ /* eslint react/prop-types: 0 */ import React, { useEffect, useState } from 'react'; import debounce from 'lodash/debounce'; -import styled from 'styled-components'; import { DOMSerializer, DOMParser } from 'prosemirror-model'; @@ -43,12 +42,6 @@ const createPlaceholder = placeholder => { return Placeholder({ content: placeholder }); }; -const LayoutWrapper = styled.div` - display: flex; - flex-direction: column; - height: 99%; -`; - const Wax = props => { let finalPlugins = []; const [application, setApplication] = useState(); @@ -125,24 +118,23 @@ const Wax = props => { const WaxRender = Layout.layoutComponent; return ( - <LayoutWrapper className={`${className}`}> - <WaxProvider app={application}> - <WaxView - autoFocus={autoFocus} - readonly={readonly} - options={WaxOptions} - placeholder={placeholder} - fileUpload={fileUpload} - onBlur={onBlur || (v => true)} - onChange={finalOnChange || (v => true)} - debug={debug} - TrackChange={TrackChange} - user={user} - > - {({ editor }) => <WaxRender editor={editor} />} - </WaxView> - </WaxProvider> - </LayoutWrapper> + <WaxProvider app={application}> + <WaxView + autoFocus={autoFocus} + readonly={readonly} + options={WaxOptions} + placeholder={placeholder} + fileUpload={fileUpload} + onBlur={onBlur || (v => true)} + onChange={finalOnChange || (v => true)} + debug={debug} + TrackChange={TrackChange} + user={user} + > + {({ editor }) => <WaxRender className={className} editor={editor} />} + </WaxView> + </WaxProvider> ); }; + export default Wax; diff --git a/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js b/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js index b9f23cd1d..c58bfb341 100644 --- a/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js +++ b/wax-prosemirror-layouts/src/layouts/EditoriaLayout.js @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import styled, { ThemeProvider } from 'styled-components'; +import styled, { css, ThemeProvider } from 'styled-components'; import PanelGroup from 'react-panelgroup'; import { InfoArea } from 'wax-prosemirror-components'; import { componentPlugin } from 'wax-prosemirror-services'; @@ -8,13 +8,7 @@ import { DocumentHelpers } from 'wax-prosemirror-utilities'; import { WaxContext } from 'wax-prosemirror-core'; import EditorElements from './EditorElements'; -const Wrapper = styled.div` - display: flex; - flex-direction: column; - height: 100%; - width: 100%; - overflow: hidden; - +const divider = css` .divider { &:before { content: 'Notes'; @@ -62,58 +56,23 @@ const Wrapper = styled.div` } `; -const Main = styled.div` - display: flex; - flex-grow: 1; - /* flex-direction: row; */ - /* height: 100%; */ - /* width: 100%; */ -`; - -const WaxSurfaceContainer = styled.div` - flex: 1; - position: relative; - z-index: 1; +const Wrapper = styled.div` display: flex; flex-direction: column; + height: 100%; width: 100%; -`; + overflow: hidden; -const EditorContainer = styled.div` - width: 65%; - height: 100%; - .ProseMirror { - -moz-box-shadow: 0 0 8px #ecedf1; - -webkit-box-shadow: 0 0 8px #ecedf1; - box-shadow: 0 0 8px #ecedf1; - min-height: 90%; - padding: 30px 30px 30px 30px; - @media (max-width: 600px) { - padding: 65px 10px 10px 10px; - } - } - @media (max-width: 600px) { - width: 95%; - } + ${divider} `; -const WaxSurfaceScroll = styled.div` - bottom: 0; - left: 0; - overflow: auto; - position: absolute; +const Main = styled.div` display: flex; - right: 0; - top: 0; - box-sizing: border-box; - padding: 0 2px 2px 2px; - height: 100%; - ${EditorElements}; + flex-grow: 1; `; const TopMenu = styled.div` - background: #fff; display: flex; justify-content: center; min-height: 40px; @@ -134,9 +93,8 @@ const TopMenu = styled.div` `; const SideMenu = styled.div` - display: flex; - border-right: 1px solid gray; - /* width: 14%; */ + border-right: 1px solid #ecedf1; + min-width: 250px; height: 100%; @media (max-width: 600px) { @@ -144,27 +102,45 @@ const SideMenu = styled.div` } `; -// const SideMenuInner = styled.div` -// display: flex; -// width: 100%; -// > div { -// flex: 1; -// display: flex; -// flex-direction: column; -// justify-content: flex-start; -// margin-top: 15px; -// button { -// display: flex; -// flex-direction: column; -// font-family: ${props => props.theme.fontInterface}; -// margin-left: 5%; -// width: 90%; -// } -// [data-name='Display'] { -// border-right: none; -// } -// } -// `; +const EditorArea = styled.div` + flex-grow: 1; +`; + +const WaxSurfaceScroll = styled.div` + overflow-y: auto; + display: flex; + box-sizing: border-box; + padding: 0 2px 2px 2px; + height: 100%; + + ${EditorElements}; +`; + +const EditorContainer = styled.div` + width: 65%; + height: 100%; + + .ProseMirror { + box-shadow: 0 0 8px #ecedf1; + min-height: 90%; + padding: 40px; + } + + @media (max-width: 600px) { + width: 100%; + } +`; + +const CommentsContainer = styled.div` + display: flex; + flex-direction: column; + width: 35%; + height: 100%; + + @media (max-width: 600px) { + width: auto; + } +`; const NotesAreaContainer = styled.div` display: flex; @@ -183,18 +159,9 @@ const NotesContainer = styled.div` height: 100%; width: 65%; position: relative; - @media (max-width: 600px) { - width: 100%; - } -`; -const CommentsContainer = styled.div` - display: flex; - flex-direction: column; - width: 35%; - height: 100%; @media (max-width: 600px) { - width: auto; + width: 100%; } `; @@ -216,35 +183,19 @@ const hasNotes = main => { }; const LeftSideBar = componentPlugin('leftSideBar'); -const RightSideBar = componentPlugin('rightSideBar'); +// const RightSideBar = componentPlugin('rightSideBar'); const TopBar = componentPlugin('topBar'); const NotesArea = componentPlugin('notesArea'); const RightArea = componentPlugin('rightArea'); const WaxOverlays = componentPlugin('waxOverlays'); -const withNotes = () => { - return ( - <NotesAreaContainer> - <NotesContainer id="notes-container"> - <NotesArea /> - </NotesContainer> - <CommentsContainer> - <RightArea area="notes" /> - </CommentsContainer> - </NotesAreaContainer> - ); -}; - const EditoriaLayout = ({ editor }) => { const { view: { main }, } = useContext(WaxContext); - let AreasWithNotes = null; - if (main) { - const notes = hasNotes(main); - if (notes.length) AreasWithNotes = withNotes(); - } + const notes = main && hasNotes(main); + const showNotes = notes && notes.length && notes.length > 0; return ( <ThemeProvider theme={cokoTheme}> @@ -255,30 +206,37 @@ const EditoriaLayout = ({ editor }) => { <Main> <SideMenu> - {/* <SideMenuInner> */} <LeftSideBar /> - {/* </SideMenuInner> */} </SideMenu> - <PanelGroup - direction="column" - panelWidths={[ - { size: surfaceHeight, resize: 'dynamic' }, - { size: notesHeight, resize: 'stretch' }, - ]} - onResizeEnd={onResizeEnd} - > - <WaxSurfaceContainer> - <WaxSurfaceScroll className="wax-surface-scroll"> + <EditorArea> + <PanelGroup + direction="column" + panelWidths={[ + { size: surfaceHeight, resize: 'stretch' }, + { size: notesHeight, resize: 'stretch' }, + ]} + onResizeEnd={onResizeEnd} + > + <WaxSurfaceScroll> <EditorContainer>{editor}</EditorContainer> <CommentsContainer> <RightArea area="main" /> </CommentsContainer> </WaxSurfaceScroll> - <RightSideBar /> - </WaxSurfaceContainer> - {AreasWithNotes} - </PanelGroup> + + {showNotes && ( + <NotesAreaContainer> + <NotesContainer id="notes-container"> + <NotesArea /> + </NotesContainer> + <CommentsContainer> + <RightArea area="notes" /> + </CommentsContainer> + </NotesAreaContainer> + )} + </PanelGroup> + </EditorArea> </Main> <InfoArea /> diff --git a/wax-prosemirror-services/src/WaxToolGroups/DisplayTextToolGroupService/DisplayText.js b/wax-prosemirror-services/src/WaxToolGroups/DisplayTextToolGroupService/DisplayText.js index 9d48314e4..df6bb97bf 100644 --- a/wax-prosemirror-services/src/WaxToolGroups/DisplayTextToolGroupService/DisplayText.js +++ b/wax-prosemirror-services/src/WaxToolGroups/DisplayTextToolGroupService/DisplayText.js @@ -1,7 +1,14 @@ import React from 'react'; import { injectable, inject } from 'inversify'; -import { LeftMenuTitle } from 'wax-prosemirror-components'; +import { BlockLevelTools, Tabs, ToolGroups } from 'wax-prosemirror-components'; import ToolGroup from '../../lib/ToolGroup'; +import { isEmpty } from 'lodash'; +import styled from 'styled-components'; + +const Empty = styled.div` + background: khaki; + height: 100%; +`; @injectable() class DisplayText extends ToolGroup { @@ -10,12 +17,42 @@ class DisplayText extends ToolGroup { constructor(@inject('Display') display, @inject('Text') text) { super(); - this.toolGroups = [{ tabA: [display, text] }]; + this.toolGroups = [ + { + name: 'TabA', + groups: [display, text], + }, + ]; } renderTools(view) { - console.log(this._toolGroups); - return <span>hi</span>; + if (isEmpty(view)) return null; + + const first = { + id: '1', + icon: 'title', + component: ( + <BlockLevelTools + groups={this._toolGroups[0].groups.map(group => { + console.log(group); + return { + groupName: group.title.props.title, + items: group._tools, + }; + })} + view={view} + /> + ), + }; + + const second = { + id: '2', + icon: 'code', + component: <Empty />, + }; + + const tabList = [first, second]; + return <Tabs tabList={tabList} />; } } -- GitLab