diff --git a/editors/editoria/src/Editoria.js b/editors/editoria/src/Editoria.js index ef823aeea687d8da82430783ebd5bb28329c704f..e7b51cea453085c9ac746cb67af35e0bfb83900c 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 831f803db44ee5ad6f46864591c1b51c27a7c4da..20a7d444f7ee72b434968829e04017e55cb634e7 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 8dce998f1bda096026f6701da6487856cea6efbe..4074ccc2b7ebf983efd97c82abf1e9bfa7520b78 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 11aab0380dc6ec3eb9e9ddc03ac2ac98e2b3251d..0742df29fae1f35d3485ca5b54e9f5bd1c005f7e 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 fe3d20e3650800172d85815174698d8e598c01e0..e1f76123f4a036cafde8a7043137a80aa54f3bc7 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 89e6a68864b185a8577f788d69c66445bf23665c..c7f654f19706b0ea713cbb1d7820e1f4b09437aa 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 1ff4cdeec6bfdeb33c47d24f1099211393a03d7e..c8e85303516d17419bb904f16eec1d5a8a144bb3 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 f04ec851326eaa62e652e878fc25429c8f8be30c..9c640c5b564e72dfb6e3020bc02b9b4ebb8e7cb2 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 e18efcae66230aa23325c1eba879b61b1ad0bc90..f52e7b5b8d47c4fa42aa27cc5e36242fb16f7ab2 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 1d56c32eca113a4f964c0d30648181c4fe882e78..e2751296d4afc136c8bae37b6d97f3a641398055 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 0cc74c051c84a69802f4f3b5c909ff95f0c3273c..a97c6c3afe14f9fcb2e038e5590f7a99ab740240 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 b9f23cd1d8714eba32d7be609d890af30d5302c2..c58bfb34185c8b1f285d29be88cfe7d1bf310b2b 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 9d48314e458ce9058960fbaa7ba2f350bc06c01a..df6bb97bf00bb6377685c7fc4bb9e7fd8eedd9db 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} />; } }