Commit db253fce authored by Christos's avatar Christos
Browse files

Merge branch 'ui-components' into 'master'

Ui components

See merge request wax/wax-prosemirror!201
parents c47ae53e 63a16752
......@@ -58,10 +58,9 @@ const Editoria = () => {
autoFocus
placeholder="Type Something..."
fileUpload={file => renderImage(file)}
// value={demo}
value={'<title>hiii</title>'}
value={demo}
layout={layout}
onChange={source => console.log(source)}
// onChange={source => console.log(source)}
user={user}
/>
</>
......
......@@ -28,6 +28,10 @@ import {
MathService,
FindAndReplaceService,
TrackingAndEditingToolGroupService,
FullScreenService,
FullScreenToolGroupService,
SpecialCharactersService,
SpecialCharactersToolGroupService,
} from 'wax-prosemirror-services';
import { DefaultSchema } from 'wax-prosemirror-utilities';
......@@ -43,7 +47,7 @@ import invisibles, {
export default {
MenuService: [
{
templateArea: 'topBar',
templateArea: 'mainMenuToolBar',
toolGroups: [
'Base',
{
......@@ -53,15 +57,34 @@ export default {
'Notes',
'Lists',
'Images',
'SpecialCharacters',
'CodeBlock',
'Tables',
'TrackingAndEditing',
'FullScreen',
],
},
{
templateArea: 'leftSideBar',
toolGroups: ['DisplayText'],
},
{
templateArea: 'commentTrackToolBar',
toolGroups: [
{
name: 'Annotations',
more: [
'Superscript',
'Subscript',
'SmallCaps',
'Emphasis',
'Code',
'Underline',
'StrikeThrough',
],
},
],
},
],
SchemaService: DefaultSchema,
......@@ -107,5 +130,9 @@ export default {
new MathService(),
new FindAndReplaceService(),
new TrackingAndEditingToolGroupService(),
new FullScreenService(),
new FullScreenToolGroupService(),
new SpecialCharactersService(),
new SpecialCharactersToolGroupService(),
],
};
......@@ -15,7 +15,6 @@ export default css`
background: white;
counter-reset: footnote;
line-height: 1.6;
font-size: 14px;
${fontWriting}
p::selection,
......
......@@ -60,10 +60,16 @@ const TopMenu = styled.div`
${th('colorFurniture')};
}
> div:last-child {
> div:nth-last-of-type(-n+2) {
margin-left: auto;
margin-right: 10px;
}
> div:last-child {
margin-left: 0;
margin-right: ${grid(5)};
}
> div[data-name="Tables"]{
border-right: none;
}
......@@ -116,6 +122,20 @@ const CommentsContainerNotes = styled.div`
height: 100%;
`;
const CommentTrackTools = styled.div`
padding: ${grid(2)}0 0 0;
position: fixed;
display: flex;
margin-left: 5px;
z-index: 1;
height: 30px;
width: 29.4%;
background: #fff;
span {
margin-left: auto;
}
`;
const NotesAreaContainer = styled.div`
background: #fff;
display: flex;
......@@ -159,9 +179,10 @@ const getNotes = main => {
};
const LeftSideBar = ComponentPlugin('leftSideBar');
const TopBar = ComponentPlugin('topBar');
const MainMenuToolBar = ComponentPlugin('mainMenuToolBar');
const NotesArea = ComponentPlugin('notesArea');
const RightArea = ComponentPlugin('rightArea');
const CommentTrackToolBar = ComponentPlugin('commentTrackToolBar');
const WaxOverlays = ComponentPlugin('waxOverlays');
const EditoriaLayout = ({ editor }) => {
......@@ -189,7 +210,7 @@ const EditoriaLayout = ({ editor }) => {
<ThemeProvider theme={cokoTheme}>
<Wrapper>
<TopMenu>
<TopBar />
<MainMenuToolBar />
</TopMenu>
<Main>
......@@ -209,6 +230,12 @@ const EditoriaLayout = ({ editor }) => {
<WaxSurfaceScroll>
<EditorContainer>{editor}</EditorContainer>
<CommentsContainer>
<CommentTrackTools>
<span>
58 COMMENTS AND SUGGESTIONS
<CommentTrackToolBar />
</span>
</CommentTrackTools>
<RightArea area="main" />
</CommentsContainer>
</WaxSurfaceScroll>
......
......@@ -15,3 +15,5 @@ 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';
export { default as FindAndReplaceTool } from './src/components/findAndReplace/FindAndReplaceTool';
export { default as FullScreen } from './src/components/FullScreen';
export { default as SpecialCharactersTool } from './src/components/specialCharacters/SpecialCharactersTool';
......@@ -4,7 +4,7 @@
"version": "0.0.26",
"description": "Wax prosemirror UI components",
"license": "MIT",
"main": "dist/index.js",
"main": "index.js",
"files": [
"dist"
],
......
/* eslint react/prop-types: 0 */
import React, { useContext, useMemo } from 'react';
import { WaxContext } from 'wax-prosemirror-core';
import MenuButton from '../ui/buttons/MenuButton';
const Button = ({ view = {}, item }) => {
const { active, enable, icon, label, onlyOnMain, run, select, title } = item;
const { active, icon, label, onlyOnMain, run, select, title } = item;
const {
view: { main },
......@@ -22,8 +21,9 @@ const Button = ({ view = {}, item }) => {
run(editorState, dispatch);
};
const isActive = active(state, activeViewId) && select(state, activeViewId);
const isActive = !!(
active(state, activeViewId) && select(state, activeViewId)
);
const isDisabled = !select(state, activeViewId, activeView);
const MenuButtonComponent = useMemo(
......
/* eslint react/prop-types: 0 */
import React, { useContext, useMemo } from 'react';
import { WaxContext } from 'wax-prosemirror-core';
import MenuButton from '../ui/buttons/MenuButton';
const Button = ({ view = {}, item }) => {
const { active, icon, label, onlyOnMain, run, select, title } = item;
const {
view: { main },
activeViewId,
activeView,
} = useContext(WaxContext);
if (onlyOnMain) view = main;
const { dispatch, state } = view;
const handleMouseDown = (e, editorState, editorDispatch) => {
e.preventDefault();
run(editorState, dispatch);
};
const isActive = active(state, activeViewId) && select(state, activeViewId);
const isDisabled = !select(state, activeViewId, activeView);
const MenuButtonComponent = useMemo(
() => (
<MenuButton
active={false}
disabled={false}
iconName={icon}
label={label}
onMouseDown={e => handleMouseDown(e, view.state, view.dispatch)}
title={title}
/>
),
[isActive, isDisabled],
);
return MenuButtonComponent;
};
export default Button;
......@@ -20,15 +20,10 @@ const DropWrapper = styled.div`
`;
const FindAndReplaceTool = ({ view = {}, item }) => {
const { state } = view;
const { enable, icon, run, select, title } = item;
const { icon, title } = item;
const dropElement = useRef();
const [isOpen, setIsOpen] = useState(false);
// const isDisabled =
// enable && !enable(state) && !(select && select(state, activeViewId));
//
let styles = { right: '-205px' };
const [style, setStyle] = useState(styles);
......
/* eslint react/prop-types: 0 */
import React, { useRef, useEffect, useState, useContext } from 'react';
import styled from 'styled-components';
import { grid, th } from '@pubsweet/ui-toolkit';
import { WaxContext } from 'wax-prosemirror-core';
import { DocumentHelpers } from 'wax-prosemirror-utilities';
const Wrapper = styled.div`
background: silver;
display: inline-block;
padding: 12px;
background: #fff;
background: #fff;
border-radius: 1.03093% / 8%;
box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px 0px,
rgba(9, 30, 66, 0.31) 0px 0px 1px 0px;
transform-origin: 50% 50% 0px;
padding: ${grid(2)} ${grid(1)} ${grid(2)} ${grid(2)};
a {
color: unset;
color: #3a4863;
text-decoration: none;
}
`;
......@@ -35,10 +40,18 @@ const ButtonGroup = styled.div`
const StyledButton = styled.button`
margin-right: 10px;
background: #777;
background: ${th('colorPrimary')};
cursor: pointer;
color: #fff;
`;
const StyledButtonCancel = styled.button`
margin-right: 10px;
background: #fff
cursor: pointer;
color:${th('colorPrimary')};;
`;
const LinkComponent = ({ mark, setPosition, position }) => {
const href = mark ? mark.attrs.href : null;
const linkMark = mark ? mark : null;
......@@ -202,9 +215,9 @@ const LinkComponent = ({ mark, setPosition, position }) => {
Apply
</StyledButton>
<StyledButton onClick={editLinkHref} type="button">
<StyledButtonCancel onClick={editLinkHref} type="button">
Cancel
</StyledButton>
</StyledButtonCancel>
</>
)}
......@@ -214,9 +227,9 @@ const LinkComponent = ({ mark, setPosition, position }) => {
Edit
</StyledButton>
<StyledButton onClick={removeLink} type="button">
<StyledButtonCancel onClick={removeLink} type="button">
Remove
</StyledButton>
</StyledButtonCancel>
</>
)}
</ButtonGroup>
......
/* eslint react/prop-types: 0 */
import React, { useRef, useState, useContext } from 'react';
import styled from 'styled-components';
import { grid } from '@pubsweet/ui-toolkit';
import { v4 as uuidv4 } from 'uuid';
import { WaxContext } from 'wax-prosemirror-core';
import { filter, groupBy } from 'lodash';
import Icon from '../../helpers/Icon';
import CharactersList from './CharactersList';
const Wrapper = styled.div`
width: 400px;
height: 220px;
overflow: hidden;
background: #fff;
display: flex;
flex-direction: column;
font-size: 14px;
box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px 0px,
rgba(9, 30, 66, 0.31) 0px 0px 1px 0px;
transform-origin: 50% 50% 0px;
`;
const SearchInputContainer = styled.div`
padding: ${grid(2)};
`;
const SearchInput = styled.input`
font-size: 15px;
font-weight: 400;
border-radius: 2px;
border: none;
padding: ${grid(1)} ${grid(10)} ${grid(1)} ${grid(1)};
width: 88%;
box-shadow: inset 0 0 0 1px rgba(27, 43, 75, 0.28);
::placeholder {
color: #d8dae0;
}
&:focus {
outline: none;
}
`;
const CharactersListComponent = styled.div`
height: 150px;
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: hidden;
padding-top: ${grid(2)};
`;
const SpecialCharactersGroup = styled.div`
display: flex;
flex-direction: column;
`;
const GroupTitle = styled.div`
font-size: 16px;
padding: 0 ${grid(2)} ${grid(2)} ${grid(2)};
`;
const GroupCharacters = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
`;
const SpecialCharacter = styled.div`
margin: ${grid(1)};
min-width: 25px;
height: 25px;
display: inline-grid;
cursor: pointer;
border: 1px solid black;
border-radius: 50%;
span {
text-align: center;
padding-top: 3px;
}
`;
const LastUsedComponent = styled.div``;
const SpecialCharactersComponent = ({ close }) => {
const searchRef = useRef(null);
const { app, view } = useContext(WaxContext);
const [searchValue, setSearchValue] = useState('');
const groupedCharacters = groupBy(CharactersList, 'group');
const [specialCharactersList, setSpecialCharactersList] = useState(
CharactersList,
);
const onChange = () => {
setSearchValue(searchRef.current.value);
const filtertedSpecialCharacters = filter(CharactersList, value => {
console.log(value);
if (value.name.toLowerCase().includes(searchValue.toLowerCase()))
return value.name;
return false;
});
setSpecialCharactersList(filtertedSpecialCharacters);
};
const insertCharacter = () => {};
const renderList = () => {
const lists = [];
Object.keys(groupBy(specialCharactersList, 'group')).forEach(key => {
lists.push(
<SpecialCharactersGroup key={key}>
<GroupTitle> {key} </GroupTitle>
<GroupCharacters>
{groupedCharacters[key].map((item, index) => {
return (
<SpecialCharacter key={uuidv4()} onMouseDown={insertCharacter}>
<span>{item.unicode}</span>
</SpecialCharacter>
);
})}
</GroupCharacters>
</SpecialCharactersGroup>,
);
});
return <div>{lists}</div>;
};
return (
<Wrapper>
<SearchInputContainer>
<SearchInput
ref={searchRef}
type="text"
placeholder="Search"
value={searchValue}
onChange={onChange}
/>
</SearchInputContainer>
<CharactersListComponent>{renderList()}</CharactersListComponent>
<LastUsedComponent>Characters Last Used</LastUsedComponent>
</Wrapper>
);
};
export default SpecialCharactersComponent;
import React, { useMemo, useState, useRef } from 'react';
import styled from 'styled-components';
import { grid } from '@pubsweet/ui-toolkit';
import MenuButton from '../../ui/buttons/MenuButton';
import SpecialCharactersComponent from './SpecialCharactersComponent';
import useOnClickOutside from '../../helpers/useOnClickOutside';
const Wrapper = styled.div`
font-size: 0;
position: relative;
z-index: 2;
`;
const DropWrapper = styled.div`
margin-top: ${grid(1)};
position: absolute;
background: white;
top: 32px;
`;
const SpecialCharactersTool = ({ view = {}, item }) => {
const { icon, title } = item;
const [isOpen, setIsOpen] = useState(false);
const ref = useRef();
useOnClickOutside(ref, () => setIsOpen(false));
const MemorizedDropdown = useMemo(
() => (
<Wrapper ref={ref}>
<MenuButton
active={isOpen}
disabled={false}
iconName={icon}
onMouseDown={() => {
setIsOpen(!isOpen);
}}
title={title}
/>
{isOpen && (
<DropWrapper>
<SpecialCharactersComponent
close={() => {
setIsOpen(false);
}}
/>
</DropWrapper>
)}
</Wrapper>
),
[isOpen],
);
return MemorizedDropdown;
};
export default SpecialCharactersTool;
......@@ -31,7 +31,7 @@ const CreateTable = ({ view = {}, item }) => {
}
const { state } = view;
const { enable, icon, run, select, title } = item;
const { icon, run, select, title } = item;
const ref = useRef();
const [isOpen, setIsOpen] = useState(false);
......
......@@ -248,4 +248,37 @@ export default {
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</Svg>
),
fullScreen: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24" fill="none">
<title> Full screen </title>
<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
</Svg>
),
fullScreenExit: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24" fill="none">
<title> Exit full screen </title>
<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" />
</Svg>
),
specialCharacters: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24" fill="none">
<g>
<rect fill="none" height="24" width="24" x="0" />
</g>
<g>
<g>
<g>
<path d="M11.88,9.14c1.28,0.06,1.61,1.15,1.63,1.66h1.79c-0.08-1.98-1.49-3.19-3.45-3.19C9.64,7.61,8,9,8,12.14 c0,1.94,0.93,4.24,3.84,4.24c2.22,0,3.41-1.65,3.44-2.95h-1.79c-0.03,0.59-0.45,1.38-1.63,1.44C10.55,14.83,10,13.81,10,12.14 C10,9.25,11.28,9.16,11.88,9.14z M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8 s3.59-8,8-8s8,3.59,8,8S16.41,20,12,20z" />
</g>
</g>
</g>
</Svg>