Skip to content

Commit

Permalink
Feature/undo redo (premieroctet#8)
Browse files Browse the repository at this point in the history
* Switch to redux

* Undo & redo with Redux

* Fix redux persist with undo behavior

* Split redux states

* Add selected view

* Fix conflicts

Co-authored-by: Baptiste Adrien <adrien.baptiste@gmail.com>
  • Loading branch information
tlenclos and baptadn authored Feb 4, 2020
1 parent 3f242eb commit 4fefc89
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 198 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"@reach/combobox": "^0.7.3",
"@rehooks/local-storage": "^2.1.1",
"@rematch/core": "^1.3.0",
"@rematch/persist": "^1.1.6",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
Expand All @@ -32,6 +31,8 @@
"react-scripts": "3.3.0",
"react-split-pane": "^0.1.89",
"redux": "^4.0.5",
"redux-persist": "^6.0.0",
"redux-undo": "^1.0.0",
"typescript": "^3.7.5"
},
"scripts": {
Expand Down
32 changes: 25 additions & 7 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Global } from "@emotion/core";
import { HotKeys } from "react-hotkeys";
import useDispatch from "./hooks/useDispatch";
import { useSelector } from "react-redux";
import { ActionCreators as UndoActionCreators } from "redux-undo";
import { RootState } from ".";

export const COMPONENTS: ComponentType[] = [
Expand Down Expand Up @@ -80,21 +81,20 @@ export const rootComponents = COMPONENTS.filter(
const keyMap = {
DELETE_NODE: "backspace",
TOGGLE_BUILDER_MODE: "b",
TOGGLE_CODE_PANEL: "c"
TOGGLE_CODE_PANEL: "c",
UNDO: ["ctrl+z", "cmd+z"],
REDO: ["ctrl+y", "cmd+y"]
};

const App = () => {
const selectedId = useSelector((state: RootState) => state.app.selectedId);
const selected = useSelector((state: RootState) => state.app.selected);
const dispatch = useDispatch();

const deleteNode = (event: KeyboardEvent | undefined) => {
if (event) {
event.preventDefault();
}

if (selectedId) {
dispatch.app.deleteComponent(selectedId);
}
dispatch.components.deleteComponent(selected.id);
};

const toggleBuilderMode = (event: KeyboardEvent | undefined) => {
Expand All @@ -111,10 +111,28 @@ const App = () => {
dispatch.app.toggleCodePanel();
};

const undo = (event: KeyboardEvent | undefined) => {
if (event) {
event.preventDefault();
}

dispatch(UndoActionCreators.undo());
};

const redo = (event: KeyboardEvent | undefined) => {
if (event) {
event.preventDefault();
}

dispatch(UndoActionCreators.redo());
};

const handlers = {
DELETE_NODE: deleteNode,
TOGGLE_BUILDER_MODE: toggleBuilderMode,
TOGGLE_CODE_PANEL: toggleCodePanel
TOGGLE_CODE_PANEL: toggleCodePanel,
UNDO: undo,
REDO: redo
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/CodePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { RootState } from "..";
import { useSelector } from "react-redux";

const CodePanel = () => {
const components = useSelector((state: RootState) => state.app.components);
const components = useSelector((state: RootState) => state.components.present.components);
const code = generateCode(components);

const { onCopy, hasCopied } = useClipboard(code);
Expand Down
6 changes: 4 additions & 2 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import { useSelector } from "react-redux";
import { RootState } from "..";

const CodeSandboxButton = () => {
const components = useSelector((state: RootState) => state.app.components);
const components = useSelector(
(state: RootState) => state.components.present.components
);

return (
<Button
Expand Down Expand Up @@ -113,7 +115,7 @@ const Header = () => {
size="xs"
variant="ghost"
onClick={() => {
dispatch.app.reset();
dispatch.components.reset();
}}
>
Reset
Expand Down
2 changes: 1 addition & 1 deletion src/components/editor/ComponentPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const ComponentPreview: React.FC<{ componentName: string }> = ({
componentName
}) => {
const component = useSelector(
(state: RootState) => state.app.components[componentName]
(state: RootState) => state.components.present.components[componentName]
);
const type = (component && component.type) || null;

Expand Down
22 changes: 20 additions & 2 deletions src/components/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ const Editor: React.FC = () => {
const showCode = useSelector((state: RootState) => state.app.showCode);
const showLayout = useSelector((state: RootState) => state.app.showLayout);
const overlay = useSelector((state: RootState) => state.app.overlay);
const components = useSelector((state: RootState) => state.app.components);
const selected = useSelector((state: RootState) => state.app.selected);
const components = useSelector(
(state: RootState) => state.components.present.components
);
const dispatch = useDispatch();

const { drop } = useDropComponent("root");
Expand Down Expand Up @@ -48,7 +51,7 @@ const Editor: React.FC = () => {
Drag some component to start coding without code! Or load a{" "}
<Link
onClick={() => {
dispatch.app.loadDemo();
dispatch.components.loadDemo();
}}
textDecoration="underline"
>
Expand Down Expand Up @@ -80,6 +83,21 @@ const Editor: React.FC = () => {
</Badge>
</Box>
)}

{selected && selected.rect && (
<Box
pointerEvents="none"
cursor="pointer"
zIndex={40}
borderWidth={1}
borderColor="red.200"
position="absolute"
width={selected.rect.width + 10}
height={selected.rect.height + 10}
top={`${selected.rect.top - 53}px`}
left={`${selected.rect.left - 229}px`}
/>
)}
</Box>
);

Expand Down
2 changes: 1 addition & 1 deletion src/components/editor/previews/AvatarPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const AvatarPreview: React.FC<IPreviewProps & {
export const AvatarGroupPreview = ({ component }: IPreviewProps) => {
const { props, ref } = useInteractive(component, true);
const { drop, isOver } = useDropComponent(component.id, ["Avatar"]);
const components = useSelector((state: RootState) => state.app.components);
const components = useSelector((state: RootState) => state.components.present.components);
let boxProps: any = { display: "inline" };

if (isOver) {
Expand Down
12 changes: 7 additions & 5 deletions src/components/inspector/Inspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import { Tooltip } from "@chakra-ui/core";

const Inspector = () => {
const dispatch = useDispatch();
const selectedId = useSelector((state: RootState) => state.app.selectedId);
const component = useSelector(
(state: RootState) => state.app.components[selectedId]
(state: RootState) =>
state.components.present.components[state.app.selected.id]
);

if (selectedId === "root" || !component) {
if (!component || component.id === "root") {
return (
<Flex
alignItems="center"
Expand Down Expand Up @@ -63,7 +63,7 @@ const Inspector = () => {
size="xs"
variant="ghost"
aria-label="Reset"
onClick={() => dispatch.app.resetProps(component.id)}
onClick={() => dispatch.components.resetProps(component.id)}
icon={IoMdRefresh}
/>
</Tooltip>
Expand All @@ -86,7 +86,9 @@ const Inspector = () => {
<IconButton
size="xs"
variant="ghost"
onClick={() => dispatch.app.deleteComponent(component.id)}
onClick={() =>
dispatch.components.deleteComponent(component.id)
}
aria-label="Remove"
icon={FiTrash2}
/>
Expand Down
Loading

0 comments on commit 4fefc89

Please sign in to comment.