Stubs alignment distribution stretch

This commit is contained in:
Steve Ruiz 2021-05-26 20:20:52 +01:00
parent 733acfaf3a
commit ab50d76e6e
13 changed files with 339 additions and 56 deletions

View file

@ -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 (
<Container>
<IconButton onClick={alignTop}>
<AlignTopIcon />
</IconButton>
<IconButton onClick={alignCenterVertical}>
<AlignCenterVerticallyIcon />
</IconButton>
<IconButton onClick={alignBottom}>
<AlignBottomIcon />
</IconButton>
<IconButton onClick={stretchVertically}>
<StretchVerticallyIcon />
</IconButton>
<IconButton onClick={distributeVertically}>
<SpaceEvenlyVerticallyIcon />
</IconButton>
<IconButton onClick={alignLeft}>
<AlignLeftIcon />
</IconButton>
<IconButton onClick={alignCenterHorizontal}>
<AlignCenterHorizontallyIcon />
</IconButton>
<IconButton onClick={alignRight}>
<AlignRightIcon />
</IconButton>
<IconButton onClick={stretchHorizontally}>
<StretchHorizontallyIcon />
</IconButton>
<IconButton onClick={distributeHorizontally}>
<SpaceEvenlyHorizontallyIcon />
</IconButton>
</Container>
)
}
const Container = styled("div", {
display: "grid",
padding: 4,
gridTemplateColumns: "repeat(5, auto)",
[`& ${IconButton}`]: {
color: "$text",
},
[`& ${IconButton} > svg`]: {
fill: "red",
stroke: "transparent",
},
})

View file

@ -92,15 +92,15 @@ const CurrentColor = styled(DropdownMenu.Trigger, {
outline: "none", outline: "none",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
padding: "8px 8px 8px 12px", padding: "4px 6px 4px 12px",
"&::before": { "&::before": {
content: "''", content: "''",
position: "absolute", position: "absolute",
top: 4, top: 0,
left: 4, left: 4,
right: 4, right: 4,
bottom: 4, bottom: 0,
pointerEvents: "none", pointerEvents: "none",
zIndex: -1, zIndex: -1,
}, },

View file

@ -8,6 +8,7 @@ import { deepCompare, deepCompareArrays, getSelectedShapes } from "utils/utils"
import { colors } from "state/data" import { colors } from "state/data"
import ColorPicker from "./color-picker" import ColorPicker from "./color-picker"
import AlignDistribute from "./align-distribute"
import { ShapeByType, ShapeStyles } from "types" import { ShapeByType, ShapeStyles } from "types"
export default function StylePanel() { export default function StylePanel() {
@ -77,34 +78,32 @@ function SelectedShapeStyles({}: {}) {
</IconButton> </IconButton>
</Panel.ButtonsGroup> </Panel.ButtonsGroup>
</Panel.Header> </Panel.Header>
<Panel.Content> <Content>
<ColorsRow> <ColorPicker
<ColorPicker label="Fill"
label="Fill" color={shapesStyle.fill}
color={shapesStyle.fill} onChange={(color) => state.send("CHANGED_STYLE", { fill: color })}
onChange={(color) => state.send("CHANGED_STYLE", { fill: color })} />
/> <ColorPicker
<ColorPicker label="Stroke"
label="Stroke" color={shapesStyle.stroke}
color={shapesStyle.stroke} onChange={(color) => state.send("CHANGED_STYLE", { stroke: color })}
onChange={(color) => state.send("CHANGED_STYLE", { stroke: color })} />
/> <AlignDistribute />
</ColorsRow> </Content>
</Panel.Content>
</Panel.Layout> </Panel.Layout>
) )
} }
const StylePanelRoot = styled(Panel.Root, { const StylePanelRoot = styled(Panel.Root, {
maxWidth: 260, minWidth: 1,
width: 184,
maxWidth: 184,
position: "relative", position: "relative",
variants: { variants: {
isOpen: { isOpen: {
true: { true: {},
width: "auto",
minWidth: 300,
},
false: { false: {
height: 34, height: 34,
width: 34, width: 34,
@ -113,7 +112,6 @@ const StylePanelRoot = styled(Panel.Root, {
}, },
}) })
const ColorsRow = styled("div", { const Content = styled(Panel.Content, {
display: "grid", padding: 8,
gridTemplateColumns: "1fr 1fr",
}) })

View file

@ -1,5 +1,6 @@
import { useEffect } from "react" import { useEffect } from "react"
import state from "state" import state from "state"
import { MoveType } from "types"
import { getKeyboardEventInfo, metaKey } from "utils/utils" import { getKeyboardEventInfo, metaKey } from "utils/utils"
export default function useKeyboardEvents() { export default function useKeyboardEvents() {
@ -47,25 +48,37 @@ export default function useKeyboardEvents() {
} }
case "": { case "": {
if (metaKey(e)) { if (metaKey(e)) {
state.send("MOVED_TO_FRONT", getKeyboardEventInfo(e)) state.send("MOVED", {
...getKeyboardEventInfo(e),
type: MoveType.ToFront,
})
} }
break break
} }
case "“": { case "“": {
if (metaKey(e)) { if (metaKey(e)) {
state.send("MOVED_TO_BACK", getKeyboardEventInfo(e)) state.send("MOVED", {
...getKeyboardEventInfo(e),
type: MoveType.ToBack,
})
} }
break break
} }
case "]": { case "]": {
if (metaKey(e)) { if (metaKey(e)) {
state.send("MOVED_FORWARD", getKeyboardEventInfo(e)) state.send("MOVED", {
...getKeyboardEventInfo(e),
type: MoveType.Forward,
})
} }
break break
} }
case "[": { case "[": {
if (metaKey(e)) { if (metaKey(e)) {
state.send("MOVED_BACKWARD", getKeyboardEventInfo(e)) state.send("MOVED", {
...getKeyboardEventInfo(e),
type: MoveType.Backward,
})
} }
break break
} }

View file

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@monaco-editor/react": "^4.1.3", "@monaco-editor/react": "^4.1.3",
"@radix-ui/react-dropdown-menu": "^0.0.19", "@radix-ui/react-dropdown-menu": "^0.0.19",
"@radix-ui/react-icons": "^1.0.3",
"@state-designer/react": "^1.7.1", "@state-designer/react": "^1.7.1",
"@stitches/react": "^0.1.9", "@stitches/react": "^0.1.9",
"framer-motion": "^4.1.16", "framer-motion": "^4.1.16",

54
state/commands/align.ts Normal file
View file

@ -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])
}
},
})
)
}

View file

@ -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])
}
},
})
)
}

View file

@ -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 transform from "./transform"
import transformSingle from "./transform-single" import transformSingle from "./transform-single"
import generate from "./generate" import translate from "./translate"
import direct from "./direct"
import rotate from "./rotate"
import move from "./move"
import style from "./style"
import deleteSelected from "./delete-selected"
const commands = { const commands = {
translate, align,
deleteSelected,
direct,
distribute,
generate,
move,
rotate,
stretch,
style,
transform, transform,
transformSingle, transformSingle,
generate, translate,
direct,
rotate,
move,
style,
deleteSelected,
} }
export default commands export default commands

38
state/commands/stretch.ts Normal file
View file

@ -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])
}
},
})
)
}

View file

@ -28,6 +28,9 @@ import {
CodeControl, CodeControl,
MoveType, MoveType,
ShapeStyles, ShapeStyles,
DistributeType,
AlignType,
StretchType,
} from "types" } from "types"
const initialData: Data = { const initialData: Data = {
@ -78,6 +81,8 @@ const state = createState({
TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel", TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel",
CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"], CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"],
RESET_CAMERA: "resetCamera", RESET_CAMERA: "resetCamera",
ALIGNED: "alignSelection",
DISTRIBUTED: "distributeSelection",
ZOOMED_TO_FIT: "zoomCameraToFit", ZOOMED_TO_FIT: "zoomCameraToFit",
ZOOMED_TO_SELECTION: { ZOOMED_TO_SELECTION: {
if: "hasSelection", if: "hasSelection",
@ -120,10 +125,7 @@ const state = createState({
INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize", INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize",
DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize", DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize",
CHANGED_CODE_CONTROL: "updateControls", CHANGED_CODE_CONTROL: "updateControls",
MOVED_TO_FRONT: "moveSelectionToFront", MOVED: "moveSelection",
MOVED_TO_BACK: "moveSelectionToBack",
MOVED_FORWARD: "moveSelectionForward",
MOVED_BACKWARD: "moveSelectionBackward",
}, },
initial: "notPointing", initial: "notPointing",
states: { states: {
@ -675,17 +677,17 @@ const state = createState({
pushPointedIdToSelectedIds(data) { pushPointedIdToSelectedIds(data) {
data.selectedIds.add(data.pointedId) data.selectedIds.add(data.pointedId)
}, },
moveSelectionToFront(data) { moveSelection(data, payload: { type: MoveType }) {
commands.move(data, MoveType.ToFront) commands.move(data, payload.type)
}, },
moveSelectionToBack(data) { alignSelection(data, payload: { type: AlignType }) {
commands.move(data, MoveType.ToBack) commands.align(data, payload.type)
}, },
moveSelectionForward(data) { stretchSelection(data, payload: { type: StretchType }) {
commands.move(data, MoveType.Forward) commands.stretch(data, payload.type)
}, },
moveSelectionBackward(data) { distributeSelection(data, payload: { type: DistributeType }) {
commands.move(data, MoveType.Backward) commands.distribute(data, payload.type)
}, },
/* --------------------- Camera --------------------- */ /* --------------------- Camera --------------------- */

View file

@ -15,7 +15,7 @@ const { styled, global, css, theme, getCssString } = createCss({
border: "#aaa", border: "#aaa",
panel: "#fefefe", panel: "#fefefe",
hover: "#efefef", hover: "#efefef",
text: "#000", text: "#333",
input: "#f3f3f3", input: "#f3f3f3",
inputBorder: "#ddd", inputBorder: "#ddd",
}, },

View file

@ -226,6 +226,25 @@ export enum MoveType {
ToBack, ToBack,
} }
export enum AlignType {
Top,
CenterVertical,
Bottom,
Left,
CenterHorizontal,
Right,
}
export enum StretchType {
Horizontal,
Vertical,
}
export enum DistributeType {
Horizontal,
Vertical,
}
/* -------------------------------------------------- */ /* -------------------------------------------------- */
/* Code Editor */ /* Code Editor */
/* -------------------------------------------------- */ /* -------------------------------------------------- */

View file

@ -1346,6 +1346,11 @@
"@babel/runtime" "^7.13.10" "@babel/runtime" "^7.13.10"
"@radix-ui/react-use-callback-ref" "0.0.5" "@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": "@radix-ui/react-id@0.0.6":
version "0.0.6" version "0.0.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c"