Browse Source

Stubs alignment distribution stretch

main
Steve Ruiz 4 years ago
parent
commit
ab50d76e6e

+ 106
- 0
components/style-panel/align-distribute.tsx View File

1
+import {
2
+  AlignBottomIcon,
3
+  AlignCenterHorizontallyIcon,
4
+  AlignCenterVerticallyIcon,
5
+  AlignLeftIcon,
6
+  AlignRightIcon,
7
+  AlignTopIcon,
8
+  SpaceEvenlyHorizontallyIcon,
9
+  SpaceEvenlyVerticallyIcon,
10
+  StretchHorizontallyIcon,
11
+  StretchVerticallyIcon,
12
+} from "@radix-ui/react-icons"
13
+import { IconButton } from "components/shared"
14
+import state from "state"
15
+import styled from "styles"
16
+import { AlignType, DistributeType, StretchType } from "types"
17
+
18
+function alignTop() {
19
+  state.send("ALIGNED", { type: AlignType.Top })
20
+}
21
+
22
+function alignCenterVertical() {
23
+  state.send("ALIGNED", { type: AlignType.CenterVertical })
24
+}
25
+
26
+function alignBottom() {
27
+  state.send("ALIGNED", { type: AlignType.Bottom })
28
+}
29
+
30
+function stretchVertically() {
31
+  state.send("STRETCHED", { type: StretchType.Vertical })
32
+}
33
+
34
+function distributeVertically() {
35
+  state.send("DISTRIBUTED", { type: DistributeType.Vertical })
36
+}
37
+
38
+function alignLeft() {
39
+  state.send("ALIGNED", { type: AlignType.Left })
40
+}
41
+
42
+function alignCenterHorizontal() {
43
+  state.send("ALIGNED", { type: AlignType.CenterHorizontal })
44
+}
45
+
46
+function alignRight() {
47
+  state.send("ALIGNED", { type: AlignType.Right })
48
+}
49
+
50
+function stretchHorizontally() {
51
+  state.send("STRETCHED", { type: StretchType.Horizontal })
52
+}
53
+
54
+function distributeHorizontally() {
55
+  state.send("DISTRIBUTED", { type: DistributeType.Horizontal })
56
+}
57
+
58
+export default function AlignDistribute() {
59
+  return (
60
+    <Container>
61
+      <IconButton onClick={alignTop}>
62
+        <AlignTopIcon />
63
+      </IconButton>
64
+      <IconButton onClick={alignCenterVertical}>
65
+        <AlignCenterVerticallyIcon />
66
+      </IconButton>
67
+      <IconButton onClick={alignBottom}>
68
+        <AlignBottomIcon />
69
+      </IconButton>
70
+      <IconButton onClick={stretchVertically}>
71
+        <StretchVerticallyIcon />
72
+      </IconButton>
73
+      <IconButton onClick={distributeVertically}>
74
+        <SpaceEvenlyVerticallyIcon />
75
+      </IconButton>
76
+      <IconButton onClick={alignLeft}>
77
+        <AlignLeftIcon />
78
+      </IconButton>
79
+      <IconButton onClick={alignCenterHorizontal}>
80
+        <AlignCenterHorizontallyIcon />
81
+      </IconButton>
82
+      <IconButton onClick={alignRight}>
83
+        <AlignRightIcon />
84
+      </IconButton>
85
+      <IconButton onClick={stretchHorizontally}>
86
+        <StretchHorizontallyIcon />
87
+      </IconButton>
88
+      <IconButton onClick={distributeHorizontally}>
89
+        <SpaceEvenlyHorizontallyIcon />
90
+      </IconButton>
91
+    </Container>
92
+  )
93
+}
94
+
95
+const Container = styled("div", {
96
+  display: "grid",
97
+  padding: 4,
98
+  gridTemplateColumns: "repeat(5, auto)",
99
+  [`& ${IconButton}`]: {
100
+    color: "$text",
101
+  },
102
+  [`& ${IconButton} > svg`]: {
103
+    fill: "red",
104
+    stroke: "transparent",
105
+  },
106
+})

+ 3
- 3
components/style-panel/color-picker.tsx View File

92
   outline: "none",
92
   outline: "none",
93
   alignItems: "center",
93
   alignItems: "center",
94
   justifyContent: "space-between",
94
   justifyContent: "space-between",
95
-  padding: "8px 8px 8px 12px",
95
+  padding: "4px 6px 4px 12px",
96
 
96
 
97
   "&::before": {
97
   "&::before": {
98
     content: "''",
98
     content: "''",
99
     position: "absolute",
99
     position: "absolute",
100
-    top: 4,
100
+    top: 0,
101
     left: 4,
101
     left: 4,
102
     right: 4,
102
     right: 4,
103
-    bottom: 4,
103
+    bottom: 0,
104
     pointerEvents: "none",
104
     pointerEvents: "none",
105
     zIndex: -1,
105
     zIndex: -1,
106
   },
106
   },

+ 20
- 22
components/style-panel/style-panel.tsx View File

8
 import { colors } from "state/data"
8
 import { colors } from "state/data"
9
 
9
 
10
 import ColorPicker from "./color-picker"
10
 import ColorPicker from "./color-picker"
11
+import AlignDistribute from "./align-distribute"
11
 import { ShapeByType, ShapeStyles } from "types"
12
 import { ShapeByType, ShapeStyles } from "types"
12
 
13
 
13
 export default function StylePanel() {
14
 export default function StylePanel() {
77
           </IconButton>
78
           </IconButton>
78
         </Panel.ButtonsGroup>
79
         </Panel.ButtonsGroup>
79
       </Panel.Header>
80
       </Panel.Header>
80
-      <Panel.Content>
81
-        <ColorsRow>
82
-          <ColorPicker
83
-            label="Fill"
84
-            color={shapesStyle.fill}
85
-            onChange={(color) => state.send("CHANGED_STYLE", { fill: color })}
86
-          />
87
-          <ColorPicker
88
-            label="Stroke"
89
-            color={shapesStyle.stroke}
90
-            onChange={(color) => state.send("CHANGED_STYLE", { stroke: color })}
91
-          />
92
-        </ColorsRow>
93
-      </Panel.Content>
81
+      <Content>
82
+        <ColorPicker
83
+          label="Fill"
84
+          color={shapesStyle.fill}
85
+          onChange={(color) => state.send("CHANGED_STYLE", { fill: color })}
86
+        />
87
+        <ColorPicker
88
+          label="Stroke"
89
+          color={shapesStyle.stroke}
90
+          onChange={(color) => state.send("CHANGED_STYLE", { stroke: color })}
91
+        />
92
+        <AlignDistribute />
93
+      </Content>
94
     </Panel.Layout>
94
     </Panel.Layout>
95
   )
95
   )
96
 }
96
 }
97
 
97
 
98
 const StylePanelRoot = styled(Panel.Root, {
98
 const StylePanelRoot = styled(Panel.Root, {
99
-  maxWidth: 260,
99
+  minWidth: 1,
100
+  width: 184,
101
+  maxWidth: 184,
100
   position: "relative",
102
   position: "relative",
101
 
103
 
102
   variants: {
104
   variants: {
103
     isOpen: {
105
     isOpen: {
104
-      true: {
105
-        width: "auto",
106
-        minWidth: 300,
107
-      },
106
+      true: {},
108
       false: {
107
       false: {
109
         height: 34,
108
         height: 34,
110
         width: 34,
109
         width: 34,
113
   },
112
   },
114
 })
113
 })
115
 
114
 
116
-const ColorsRow = styled("div", {
117
-  display: "grid",
118
-  gridTemplateColumns: "1fr 1fr",
115
+const Content = styled(Panel.Content, {
116
+  padding: 8,
119
 })
117
 })

+ 17
- 4
hooks/useKeyboardEvents.ts View File

1
 import { useEffect } from "react"
1
 import { useEffect } from "react"
2
 import state from "state"
2
 import state from "state"
3
+import { MoveType } from "types"
3
 import { getKeyboardEventInfo, metaKey } from "utils/utils"
4
 import { getKeyboardEventInfo, metaKey } from "utils/utils"
4
 
5
 
5
 export default function useKeyboardEvents() {
6
 export default function useKeyboardEvents() {
47
         }
48
         }
48
         case "‘": {
49
         case "‘": {
49
           if (metaKey(e)) {
50
           if (metaKey(e)) {
50
-            state.send("MOVED_TO_FRONT", getKeyboardEventInfo(e))
51
+            state.send("MOVED", {
52
+              ...getKeyboardEventInfo(e),
53
+              type: MoveType.ToFront,
54
+            })
51
           }
55
           }
52
           break
56
           break
53
         }
57
         }
54
         case "“": {
58
         case "“": {
55
           if (metaKey(e)) {
59
           if (metaKey(e)) {
56
-            state.send("MOVED_TO_BACK", getKeyboardEventInfo(e))
60
+            state.send("MOVED", {
61
+              ...getKeyboardEventInfo(e),
62
+              type: MoveType.ToBack,
63
+            })
57
           }
64
           }
58
           break
65
           break
59
         }
66
         }
60
         case "]": {
67
         case "]": {
61
           if (metaKey(e)) {
68
           if (metaKey(e)) {
62
-            state.send("MOVED_FORWARD", getKeyboardEventInfo(e))
69
+            state.send("MOVED", {
70
+              ...getKeyboardEventInfo(e),
71
+              type: MoveType.Forward,
72
+            })
63
           }
73
           }
64
           break
74
           break
65
         }
75
         }
66
         case "[": {
76
         case "[": {
67
           if (metaKey(e)) {
77
           if (metaKey(e)) {
68
-            state.send("MOVED_BACKWARD", getKeyboardEventInfo(e))
78
+            state.send("MOVED", {
79
+              ...getKeyboardEventInfo(e),
80
+              type: MoveType.Backward,
81
+            })
69
           }
82
           }
70
           break
83
           break
71
         }
84
         }

+ 1
- 0
package.json View File

10
   "dependencies": {
10
   "dependencies": {
11
     "@monaco-editor/react": "^4.1.3",
11
     "@monaco-editor/react": "^4.1.3",
12
     "@radix-ui/react-dropdown-menu": "^0.0.19",
12
     "@radix-ui/react-dropdown-menu": "^0.0.19",
13
+    "@radix-ui/react-icons": "^1.0.3",
13
     "@state-designer/react": "^1.7.1",
14
     "@state-designer/react": "^1.7.1",
14
     "@stitches/react": "^0.1.9",
15
     "@stitches/react": "^0.1.9",
15
     "framer-motion": "^4.1.16",
16
     "framer-motion": "^4.1.16",

+ 54
- 0
state/commands/align.ts View File

1
+import Command from "./command"
2
+import history from "../history"
3
+import { AlignType, Data } from "types"
4
+import { getPage } from "utils/utils"
5
+import { getShapeUtils } from "lib/shape-utils"
6
+
7
+export default function alignCommand(data: Data, type: AlignType) {
8
+  const { currentPageId } = data
9
+  const initialPoints = Object.fromEntries(
10
+    Object.entries(getPage(data).shapes).map(([id, shape]) => [
11
+      id,
12
+      [...shape.point],
13
+    ])
14
+  )
15
+
16
+  history.execute(
17
+    data,
18
+    new Command({
19
+      name: "aligned",
20
+      category: "canvas",
21
+      do(data) {
22
+        const { shapes } = getPage(data, currentPageId)
23
+
24
+        switch (type) {
25
+          case AlignType.Top: {
26
+            break
27
+          }
28
+          case AlignType.CenterVertical: {
29
+            break
30
+          }
31
+          case AlignType.Bottom: {
32
+            break
33
+          }
34
+          case AlignType.Left: {
35
+            break
36
+          }
37
+          case AlignType.CenterHorizontal: {
38
+            break
39
+          }
40
+          case AlignType.Right: {
41
+            break
42
+          }
43
+        }
44
+      },
45
+      undo(data) {
46
+        const { shapes } = getPage(data, currentPageId)
47
+        for (let id in initialPoints) {
48
+          const shape = shapes[id]
49
+          getShapeUtils(shape).translateTo(shape, initialPoints[id])
50
+        }
51
+      },
52
+    })
53
+  )
54
+}

+ 41
- 0
state/commands/distribute.ts View File

1
+import Command from "./command"
2
+import history from "../history"
3
+import { AlignType, Data, DistributeType } from "types"
4
+import { getPage } from "utils/utils"
5
+import { getShapeUtils } from "lib/shape-utils"
6
+
7
+export default function distributeCommand(data: Data, type: DistributeType) {
8
+  const { currentPageId } = data
9
+
10
+  const initialPoints = Object.fromEntries(
11
+    Object.entries(getPage(data).shapes).map(([id, shape]) => [
12
+      id,
13
+      [...shape.point],
14
+    ])
15
+  )
16
+
17
+  history.execute(
18
+    data,
19
+    new Command({
20
+      name: "distributed",
21
+      category: "canvas",
22
+      do(data) {
23
+        const { shapes } = getPage(data, currentPageId)
24
+
25
+        switch (type) {
26
+          case DistributeType.Horizontal: {
27
+          }
28
+          case DistributeType.Vertical: {
29
+          }
30
+        }
31
+      },
32
+      undo(data) {
33
+        const { shapes } = getPage(data, currentPageId)
34
+        for (let id in initialPoints) {
35
+          const shape = shapes[id]
36
+          getShapeUtils(shape).translateTo(shape, initialPoints[id])
37
+        }
38
+      },
39
+    })
40
+  )
41
+}

+ 18
- 12
state/commands/index.ts View File

1
-import translate from "./translate"
2
-import transform from "./transform"
3
-import transformSingle from "./transform-single"
4
-import generate from "./generate"
1
+import align from "./align"
2
+import deleteSelected from "./delete-selected"
5
 import direct from "./direct"
3
 import direct from "./direct"
6
-import rotate from "./rotate"
4
+import distribute from "./distribute"
5
+import generate from "./generate"
7
 import move from "./move"
6
 import move from "./move"
7
+import rotate from "./rotate"
8
+import stretch from "./stretch"
8
 import style from "./style"
9
 import style from "./style"
9
-import deleteSelected from "./delete-selected"
10
+import transform from "./transform"
11
+import transformSingle from "./transform-single"
12
+import translate from "./translate"
10
 
13
 
11
 const commands = {
14
 const commands = {
12
-  translate,
13
-  transform,
14
-  transformSingle,
15
-  generate,
15
+  align,
16
+  deleteSelected,
16
   direct,
17
   direct,
17
-  rotate,
18
+  distribute,
19
+  generate,
18
   move,
20
   move,
21
+  rotate,
22
+  stretch,
19
   style,
23
   style,
20
-  deleteSelected,
24
+  transform,
25
+  transformSingle,
26
+  translate,
21
 }
27
 }
22
 
28
 
23
 export default commands
29
 export default commands

+ 38
- 0
state/commands/stretch.ts View File

1
+import Command from "./command"
2
+import history from "../history"
3
+import { StretchType, Data } from "types"
4
+import { getPage } from "utils/utils"
5
+import { getShapeUtils } from "lib/shape-utils"
6
+
7
+export default function stretchCommand(data: Data, type: StretchType) {
8
+  const { currentPageId } = data
9
+
10
+  const initialPoints = Object.fromEntries(
11
+    Object.entries(getPage(data).shapes).map(([id, shape]) => [id, shape.point])
12
+  )
13
+
14
+  history.execute(
15
+    data,
16
+    new Command({
17
+      name: "distributed",
18
+      category: "canvas",
19
+      do(data) {
20
+        const { shapes } = getPage(data, currentPageId)
21
+
22
+        switch (type) {
23
+          case StretchType.Horizontal: {
24
+          }
25
+          case StretchType.Vertical: {
26
+          }
27
+        }
28
+      },
29
+      undo(data) {
30
+        const { shapes } = getPage(data, currentPageId)
31
+        for (let id in initialPoints) {
32
+          const shape = shapes[id]
33
+          getShapeUtils(shape).translateTo(shape, initialPoints[id])
34
+        }
35
+      },
36
+    })
37
+  )
38
+}

+ 14
- 12
state/state.ts View File

28
   CodeControl,
28
   CodeControl,
29
   MoveType,
29
   MoveType,
30
   ShapeStyles,
30
   ShapeStyles,
31
+  DistributeType,
32
+  AlignType,
33
+  StretchType,
31
 } from "types"
34
 } from "types"
32
 
35
 
33
 const initialData: Data = {
36
 const initialData: Data = {
78
     TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel",
81
     TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel",
79
     CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"],
82
     CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"],
80
     RESET_CAMERA: "resetCamera",
83
     RESET_CAMERA: "resetCamera",
84
+    ALIGNED: "alignSelection",
85
+    DISTRIBUTED: "distributeSelection",
81
     ZOOMED_TO_FIT: "zoomCameraToFit",
86
     ZOOMED_TO_FIT: "zoomCameraToFit",
82
     ZOOMED_TO_SELECTION: {
87
     ZOOMED_TO_SELECTION: {
83
       if: "hasSelection",
88
       if: "hasSelection",
120
             INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize",
125
             INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize",
121
             DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize",
126
             DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize",
122
             CHANGED_CODE_CONTROL: "updateControls",
127
             CHANGED_CODE_CONTROL: "updateControls",
123
-            MOVED_TO_FRONT: "moveSelectionToFront",
124
-            MOVED_TO_BACK: "moveSelectionToBack",
125
-            MOVED_FORWARD: "moveSelectionForward",
126
-            MOVED_BACKWARD: "moveSelectionBackward",
128
+            MOVED: "moveSelection",
127
           },
129
           },
128
           initial: "notPointing",
130
           initial: "notPointing",
129
           states: {
131
           states: {
675
     pushPointedIdToSelectedIds(data) {
677
     pushPointedIdToSelectedIds(data) {
676
       data.selectedIds.add(data.pointedId)
678
       data.selectedIds.add(data.pointedId)
677
     },
679
     },
678
-    moveSelectionToFront(data) {
679
-      commands.move(data, MoveType.ToFront)
680
+    moveSelection(data, payload: { type: MoveType }) {
681
+      commands.move(data, payload.type)
680
     },
682
     },
681
-    moveSelectionToBack(data) {
682
-      commands.move(data, MoveType.ToBack)
683
+    alignSelection(data, payload: { type: AlignType }) {
684
+      commands.align(data, payload.type)
683
     },
685
     },
684
-    moveSelectionForward(data) {
685
-      commands.move(data, MoveType.Forward)
686
+    stretchSelection(data, payload: { type: StretchType }) {
687
+      commands.stretch(data, payload.type)
686
     },
688
     },
687
-    moveSelectionBackward(data) {
688
-      commands.move(data, MoveType.Backward)
689
+    distributeSelection(data, payload: { type: DistributeType }) {
690
+      commands.distribute(data, payload.type)
689
     },
691
     },
690
 
692
 
691
     /* --------------------- Camera --------------------- */
693
     /* --------------------- Camera --------------------- */

+ 1
- 1
styles/stitches.config.ts View File

15
       border: "#aaa",
15
       border: "#aaa",
16
       panel: "#fefefe",
16
       panel: "#fefefe",
17
       hover: "#efefef",
17
       hover: "#efefef",
18
-      text: "#000",
18
+      text: "#333",
19
       input: "#f3f3f3",
19
       input: "#f3f3f3",
20
       inputBorder: "#ddd",
20
       inputBorder: "#ddd",
21
     },
21
     },

+ 19
- 0
types.ts View File

226
   ToBack,
226
   ToBack,
227
 }
227
 }
228
 
228
 
229
+export enum AlignType {
230
+  Top,
231
+  CenterVertical,
232
+  Bottom,
233
+  Left,
234
+  CenterHorizontal,
235
+  Right,
236
+}
237
+
238
+export enum StretchType {
239
+  Horizontal,
240
+  Vertical,
241
+}
242
+
243
+export enum DistributeType {
244
+  Horizontal,
245
+  Vertical,
246
+}
247
+
229
 /* -------------------------------------------------- */
248
 /* -------------------------------------------------- */
230
 /*                     Code Editor                    */
249
 /*                     Code Editor                    */
231
 /* -------------------------------------------------- */
250
 /* -------------------------------------------------- */

+ 5
- 0
yarn.lock View File

1346
     "@babel/runtime" "^7.13.10"
1346
     "@babel/runtime" "^7.13.10"
1347
     "@radix-ui/react-use-callback-ref" "0.0.5"
1347
     "@radix-ui/react-use-callback-ref" "0.0.5"
1348
 
1348
 
1349
+"@radix-ui/react-icons@^1.0.3":
1350
+  version "1.0.3"
1351
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.0.3.tgz#4ef61f1234f44991f7a19e108f77ca37032b4be2"
1352
+  integrity sha512-YbPAUZwTsvF/2H7IU35txaLUB+JNSV8GIhnswlqiFODP/P32t5op5keYUvQWsSj9TA0VLF367J24buUjIprn0w==
1353
+
1349
 "@radix-ui/react-id@0.0.6":
1354
 "@radix-ui/react-id@0.0.6":
1350
   version "0.0.6"
1355
   version "0.0.6"
1351
   resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c"
1356
   resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c"

Loading…
Cancel
Save