From ab50d76e6e55166613fcac57eff8e999cea18230 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Wed, 26 May 2021 20:20:52 +0100 Subject: [PATCH] Stubs alignment distribution stretch --- components/style-panel/align-distribute.tsx | 106 ++++++++++++++++++++ components/style-panel/color-picker.tsx | 6 +- components/style-panel/style-panel.tsx | 42 ++++---- hooks/useKeyboardEvents.ts | 21 +++- package.json | 1 + state/commands/align.ts | 54 ++++++++++ state/commands/distribute.ts | 41 ++++++++ state/commands/index.ts | 34 ++++--- state/commands/stretch.ts | 38 +++++++ state/state.ts | 26 ++--- styles/stitches.config.ts | 2 +- types.ts | 19 ++++ yarn.lock | 5 + 13 files changed, 339 insertions(+), 56 deletions(-) create mode 100644 components/style-panel/align-distribute.tsx create mode 100644 state/commands/align.ts create mode 100644 state/commands/distribute.ts create mode 100644 state/commands/stretch.ts diff --git a/components/style-panel/align-distribute.tsx b/components/style-panel/align-distribute.tsx new file mode 100644 index 000000000..29fb627c7 --- /dev/null +++ b/components/style-panel/align-distribute.tsx @@ -0,0 +1,106 @@ +import { + AlignBottomIcon, + AlignCenterHorizontallyIcon, + AlignCenterVerticallyIcon, + AlignLeftIcon, + AlignRightIcon, + AlignTopIcon, + SpaceEvenlyHorizontallyIcon, + SpaceEvenlyVerticallyIcon, + StretchHorizontallyIcon, + StretchVerticallyIcon, +} from "@radix-ui/react-icons" +import { IconButton } from "components/shared" +import state from "state" +import styled from "styles" +import { AlignType, DistributeType, StretchType } from "types" + +function alignTop() { + state.send("ALIGNED", { type: AlignType.Top }) +} + +function alignCenterVertical() { + state.send("ALIGNED", { type: AlignType.CenterVertical }) +} + +function alignBottom() { + state.send("ALIGNED", { type: AlignType.Bottom }) +} + +function stretchVertically() { + state.send("STRETCHED", { type: StretchType.Vertical }) +} + +function distributeVertically() { + state.send("DISTRIBUTED", { type: DistributeType.Vertical }) +} + +function alignLeft() { + state.send("ALIGNED", { type: AlignType.Left }) +} + +function alignCenterHorizontal() { + state.send("ALIGNED", { type: AlignType.CenterHorizontal }) +} + +function alignRight() { + state.send("ALIGNED", { type: AlignType.Right }) +} + +function stretchHorizontally() { + state.send("STRETCHED", { type: StretchType.Horizontal }) +} + +function distributeHorizontally() { + state.send("DISTRIBUTED", { type: DistributeType.Horizontal }) +} + +export default function AlignDistribute() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +const Container = styled("div", { + display: "grid", + padding: 4, + gridTemplateColumns: "repeat(5, auto)", + [`& ${IconButton}`]: { + color: "$text", + }, + [`& ${IconButton} > svg`]: { + fill: "red", + stroke: "transparent", + }, +}) diff --git a/components/style-panel/color-picker.tsx b/components/style-panel/color-picker.tsx index c958e3b03..65be1f13d 100644 --- a/components/style-panel/color-picker.tsx +++ b/components/style-panel/color-picker.tsx @@ -92,15 +92,15 @@ const CurrentColor = styled(DropdownMenu.Trigger, { outline: "none", alignItems: "center", justifyContent: "space-between", - padding: "8px 8px 8px 12px", + padding: "4px 6px 4px 12px", "&::before": { content: "''", position: "absolute", - top: 4, + top: 0, left: 4, right: 4, - bottom: 4, + bottom: 0, pointerEvents: "none", zIndex: -1, }, diff --git a/components/style-panel/style-panel.tsx b/components/style-panel/style-panel.tsx index e543fea5e..b2e2258a5 100644 --- a/components/style-panel/style-panel.tsx +++ b/components/style-panel/style-panel.tsx @@ -8,6 +8,7 @@ import { deepCompare, deepCompareArrays, getSelectedShapes } from "utils/utils" import { colors } from "state/data" import ColorPicker from "./color-picker" +import AlignDistribute from "./align-distribute" import { ShapeByType, ShapeStyles } from "types" export default function StylePanel() { @@ -77,34 +78,32 @@ function SelectedShapeStyles({}: {}) { - - - state.send("CHANGED_STYLE", { fill: color })} - /> - state.send("CHANGED_STYLE", { stroke: color })} - /> - - + + state.send("CHANGED_STYLE", { fill: color })} + /> + state.send("CHANGED_STYLE", { stroke: color })} + /> + + ) } const StylePanelRoot = styled(Panel.Root, { - maxWidth: 260, + minWidth: 1, + width: 184, + maxWidth: 184, position: "relative", variants: { isOpen: { - true: { - width: "auto", - minWidth: 300, - }, + true: {}, false: { height: 34, width: 34, @@ -113,7 +112,6 @@ const StylePanelRoot = styled(Panel.Root, { }, }) -const ColorsRow = styled("div", { - display: "grid", - gridTemplateColumns: "1fr 1fr", +const Content = styled(Panel.Content, { + padding: 8, }) diff --git a/hooks/useKeyboardEvents.ts b/hooks/useKeyboardEvents.ts index def644275..2208a06d4 100644 --- a/hooks/useKeyboardEvents.ts +++ b/hooks/useKeyboardEvents.ts @@ -1,5 +1,6 @@ import { useEffect } from "react" import state from "state" +import { MoveType } from "types" import { getKeyboardEventInfo, metaKey } from "utils/utils" export default function useKeyboardEvents() { @@ -47,25 +48,37 @@ export default function useKeyboardEvents() { } case "‘": { if (metaKey(e)) { - state.send("MOVED_TO_FRONT", getKeyboardEventInfo(e)) + state.send("MOVED", { + ...getKeyboardEventInfo(e), + type: MoveType.ToFront, + }) } break } case "“": { if (metaKey(e)) { - state.send("MOVED_TO_BACK", getKeyboardEventInfo(e)) + state.send("MOVED", { + ...getKeyboardEventInfo(e), + type: MoveType.ToBack, + }) } break } case "]": { if (metaKey(e)) { - state.send("MOVED_FORWARD", getKeyboardEventInfo(e)) + state.send("MOVED", { + ...getKeyboardEventInfo(e), + type: MoveType.Forward, + }) } break } case "[": { if (metaKey(e)) { - state.send("MOVED_BACKWARD", getKeyboardEventInfo(e)) + state.send("MOVED", { + ...getKeyboardEventInfo(e), + type: MoveType.Backward, + }) } break } diff --git a/package.json b/package.json index 3c75afe29..9d7ebf136 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dependencies": { "@monaco-editor/react": "^4.1.3", "@radix-ui/react-dropdown-menu": "^0.0.19", + "@radix-ui/react-icons": "^1.0.3", "@state-designer/react": "^1.7.1", "@stitches/react": "^0.1.9", "framer-motion": "^4.1.16", diff --git a/state/commands/align.ts b/state/commands/align.ts new file mode 100644 index 000000000..b79663834 --- /dev/null +++ b/state/commands/align.ts @@ -0,0 +1,54 @@ +import Command from "./command" +import history from "../history" +import { AlignType, Data } from "types" +import { getPage } from "utils/utils" +import { getShapeUtils } from "lib/shape-utils" + +export default function alignCommand(data: Data, type: AlignType) { + const { currentPageId } = data + const initialPoints = Object.fromEntries( + Object.entries(getPage(data).shapes).map(([id, shape]) => [ + id, + [...shape.point], + ]) + ) + + history.execute( + data, + new Command({ + name: "aligned", + category: "canvas", + do(data) { + const { shapes } = getPage(data, currentPageId) + + switch (type) { + case AlignType.Top: { + break + } + case AlignType.CenterVertical: { + break + } + case AlignType.Bottom: { + break + } + case AlignType.Left: { + break + } + case AlignType.CenterHorizontal: { + break + } + case AlignType.Right: { + break + } + } + }, + undo(data) { + const { shapes } = getPage(data, currentPageId) + for (let id in initialPoints) { + const shape = shapes[id] + getShapeUtils(shape).translateTo(shape, initialPoints[id]) + } + }, + }) + ) +} diff --git a/state/commands/distribute.ts b/state/commands/distribute.ts new file mode 100644 index 000000000..fe62c00ae --- /dev/null +++ b/state/commands/distribute.ts @@ -0,0 +1,41 @@ +import Command from "./command" +import history from "../history" +import { AlignType, Data, DistributeType } from "types" +import { getPage } from "utils/utils" +import { getShapeUtils } from "lib/shape-utils" + +export default function distributeCommand(data: Data, type: DistributeType) { + const { currentPageId } = data + + const initialPoints = Object.fromEntries( + Object.entries(getPage(data).shapes).map(([id, shape]) => [ + id, + [...shape.point], + ]) + ) + + history.execute( + data, + new Command({ + name: "distributed", + category: "canvas", + do(data) { + const { shapes } = getPage(data, currentPageId) + + switch (type) { + case DistributeType.Horizontal: { + } + case DistributeType.Vertical: { + } + } + }, + undo(data) { + const { shapes } = getPage(data, currentPageId) + for (let id in initialPoints) { + const shape = shapes[id] + getShapeUtils(shape).translateTo(shape, initialPoints[id]) + } + }, + }) + ) +} diff --git a/state/commands/index.ts b/state/commands/index.ts index 6556cc486..a3ed8444c 100644 --- a/state/commands/index.ts +++ b/state/commands/index.ts @@ -1,23 +1,29 @@ -import translate from "./translate" +import align from "./align" +import deleteSelected from "./delete-selected" +import direct from "./direct" +import distribute from "./distribute" +import generate from "./generate" +import move from "./move" +import rotate from "./rotate" +import stretch from "./stretch" +import style from "./style" import transform from "./transform" import transformSingle from "./transform-single" -import generate from "./generate" -import direct from "./direct" -import rotate from "./rotate" -import move from "./move" -import style from "./style" -import deleteSelected from "./delete-selected" +import translate from "./translate" const commands = { - translate, + align, + deleteSelected, + direct, + distribute, + generate, + move, + rotate, + stretch, + style, transform, transformSingle, - generate, - direct, - rotate, - move, - style, - deleteSelected, + translate, } export default commands diff --git a/state/commands/stretch.ts b/state/commands/stretch.ts new file mode 100644 index 000000000..9c754bef4 --- /dev/null +++ b/state/commands/stretch.ts @@ -0,0 +1,38 @@ +import Command from "./command" +import history from "../history" +import { StretchType, Data } from "types" +import { getPage } from "utils/utils" +import { getShapeUtils } from "lib/shape-utils" + +export default function stretchCommand(data: Data, type: StretchType) { + const { currentPageId } = data + + const initialPoints = Object.fromEntries( + Object.entries(getPage(data).shapes).map(([id, shape]) => [id, shape.point]) + ) + + history.execute( + data, + new Command({ + name: "distributed", + category: "canvas", + do(data) { + const { shapes } = getPage(data, currentPageId) + + switch (type) { + case StretchType.Horizontal: { + } + case StretchType.Vertical: { + } + } + }, + undo(data) { + const { shapes } = getPage(data, currentPageId) + for (let id in initialPoints) { + const shape = shapes[id] + getShapeUtils(shape).translateTo(shape, initialPoints[id]) + } + }, + }) + ) +} diff --git a/state/state.ts b/state/state.ts index f02065edc..b091b7651 100644 --- a/state/state.ts +++ b/state/state.ts @@ -28,6 +28,9 @@ import { CodeControl, MoveType, ShapeStyles, + DistributeType, + AlignType, + StretchType, } from "types" const initialData: Data = { @@ -78,6 +81,8 @@ const state = createState({ TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel", CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"], RESET_CAMERA: "resetCamera", + ALIGNED: "alignSelection", + DISTRIBUTED: "distributeSelection", ZOOMED_TO_FIT: "zoomCameraToFit", ZOOMED_TO_SELECTION: { if: "hasSelection", @@ -120,10 +125,7 @@ const state = createState({ INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize", DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize", CHANGED_CODE_CONTROL: "updateControls", - MOVED_TO_FRONT: "moveSelectionToFront", - MOVED_TO_BACK: "moveSelectionToBack", - MOVED_FORWARD: "moveSelectionForward", - MOVED_BACKWARD: "moveSelectionBackward", + MOVED: "moveSelection", }, initial: "notPointing", states: { @@ -675,17 +677,17 @@ const state = createState({ pushPointedIdToSelectedIds(data) { data.selectedIds.add(data.pointedId) }, - moveSelectionToFront(data) { - commands.move(data, MoveType.ToFront) + moveSelection(data, payload: { type: MoveType }) { + commands.move(data, payload.type) }, - moveSelectionToBack(data) { - commands.move(data, MoveType.ToBack) + alignSelection(data, payload: { type: AlignType }) { + commands.align(data, payload.type) }, - moveSelectionForward(data) { - commands.move(data, MoveType.Forward) + stretchSelection(data, payload: { type: StretchType }) { + commands.stretch(data, payload.type) }, - moveSelectionBackward(data) { - commands.move(data, MoveType.Backward) + distributeSelection(data, payload: { type: DistributeType }) { + commands.distribute(data, payload.type) }, /* --------------------- Camera --------------------- */ diff --git a/styles/stitches.config.ts b/styles/stitches.config.ts index 097ed7471..d7f495e20 100644 --- a/styles/stitches.config.ts +++ b/styles/stitches.config.ts @@ -15,7 +15,7 @@ const { styled, global, css, theme, getCssString } = createCss({ border: "#aaa", panel: "#fefefe", hover: "#efefef", - text: "#000", + text: "#333", input: "#f3f3f3", inputBorder: "#ddd", }, diff --git a/types.ts b/types.ts index 14344687b..bffd1daac 100644 --- a/types.ts +++ b/types.ts @@ -226,6 +226,25 @@ export enum MoveType { ToBack, } +export enum AlignType { + Top, + CenterVertical, + Bottom, + Left, + CenterHorizontal, + Right, +} + +export enum StretchType { + Horizontal, + Vertical, +} + +export enum DistributeType { + Horizontal, + Vertical, +} + /* -------------------------------------------------- */ /* Code Editor */ /* -------------------------------------------------- */ diff --git a/yarn.lock b/yarn.lock index d4d8846c4..e51000f0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1346,6 +1346,11 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "0.0.5" +"@radix-ui/react-icons@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.0.3.tgz#4ef61f1234f44991f7a19e108f77ca37032b4be2" + integrity sha512-YbPAUZwTsvF/2H7IU35txaLUB+JNSV8GIhnswlqiFODP/P32t5op5keYUvQWsSj9TA0VLF367J24buUjIprn0w== + "@radix-ui/react-id@0.0.6": version "0.0.6" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c"