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",
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,
},

View file

@ -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({}: {}) {
</IconButton>
</Panel.ButtonsGroup>
</Panel.Header>
<Panel.Content>
<ColorsRow>
<ColorPicker
label="Fill"
color={shapesStyle.fill}
onChange={(color) => state.send("CHANGED_STYLE", { fill: color })}
/>
<ColorPicker
label="Stroke"
color={shapesStyle.stroke}
onChange={(color) => state.send("CHANGED_STYLE", { stroke: color })}
/>
</ColorsRow>
</Panel.Content>
<Content>
<ColorPicker
label="Fill"
color={shapesStyle.fill}
onChange={(color) => state.send("CHANGED_STYLE", { fill: color })}
/>
<ColorPicker
label="Stroke"
color={shapesStyle.stroke}
onChange={(color) => state.send("CHANGED_STYLE", { stroke: color })}
/>
<AlignDistribute />
</Content>
</Panel.Layout>
)
}
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,
})

View file

@ -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
}

View file

@ -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",

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 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

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,
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 --------------------- */

View file

@ -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",
},

View file

@ -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 */
/* -------------------------------------------------- */

View file

@ -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"