diff --git a/components/icons/Redo.svg b/components/icons/Redo.svg
new file mode 100644
index 000000000..b524e86eb
--- /dev/null
+++ b/components/icons/Redo.svg
@@ -0,0 +1,4 @@
+
diff --git a/components/icons/Trash.svg b/components/icons/Trash.svg
new file mode 100644
index 000000000..aed40eb98
--- /dev/null
+++ b/components/icons/Trash.svg
@@ -0,0 +1,6 @@
+
diff --git a/components/icons/Undo.svg b/components/icons/Undo.svg
new file mode 100644
index 000000000..c47375398
--- /dev/null
+++ b/components/icons/Undo.svg
@@ -0,0 +1,4 @@
+
diff --git a/components/icons/index.tsx b/components/icons/index.tsx
new file mode 100644
index 000000000..4ce8d6300
--- /dev/null
+++ b/components/icons/index.tsx
@@ -0,0 +1,3 @@
+export { default as Redo } from './redo'
+export { default as Trash } from './trash'
+export { default as Undo } from './undo'
diff --git a/components/icons/redo.tsx b/components/icons/redo.tsx
new file mode 100644
index 000000000..84b19c0ca
--- /dev/null
+++ b/components/icons/redo.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react'
+
+function SvgRedo(props: React.SVGProps): JSX.Element {
+ return (
+
+ )
+}
+
+export default SvgRedo
diff --git a/components/icons/trash.tsx b/components/icons/trash.tsx
new file mode 100644
index 000000000..01fd1a734
--- /dev/null
+++ b/components/icons/trash.tsx
@@ -0,0 +1,33 @@
+import * as React from 'react'
+
+function SvgTrash(props: React.SVGProps): JSX.Element {
+ return (
+
+ )
+}
+
+export default SvgTrash
diff --git a/components/icons/undo.tsx b/components/icons/undo.tsx
new file mode 100644
index 000000000..70b654741
--- /dev/null
+++ b/components/icons/undo.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react'
+
+function SvgUndo(props: React.SVGProps): JSX.Element {
+ return (
+
+ )
+}
+
+export default SvgUndo
diff --git a/components/shared.tsx b/components/shared.tsx
index b15d1af82..df7a47d4d 100644
--- a/components/shared.tsx
+++ b/components/shared.tsx
@@ -7,6 +7,7 @@ import { forwardRef } from 'react'
export const breakpoints: any = { '@initial': 'mobile', '@sm': 'small' }
export const IconButton = styled('button', {
+ position: 'relative',
height: '32px',
width: '32px',
backgroundColor: '$panel',
@@ -19,6 +20,7 @@ export const IconButton = styled('button', {
outline: 'none',
border: 'none',
pointerEvents: 'all',
+ fontSize: '$0',
cursor: 'pointer',
'& > *': {
@@ -48,7 +50,9 @@ export const IconButton = styled('button', {
},
size: {
small: {
- '& svg': {
+ height: 32,
+ width: 32,
+ '& svg:nth-of-type(1)': {
height: '16px',
width: '16px',
},
@@ -56,17 +60,17 @@ export const IconButton = styled('button', {
medium: {
height: 44,
width: 44,
- '& svg': {
- height: '20px',
- width: '20px',
+ '& svg:nth-of-type(1)': {
+ height: '18px',
+ width: '18px',
},
},
large: {
height: 44,
width: 44,
- '& svg': {
- height: '24px',
- width: '24px',
+ '& svg:nth-of-type(1)': {
+ height: '20px',
+ width: '20px',
},
},
},
@@ -404,3 +408,10 @@ export const ButtonsRow = styled('div', {
justifyContent: 'flex-start',
padding: 0,
})
+
+export const VerticalDivider = styled('hr', {
+ width: '1px',
+ margin: '-2px 3px',
+ border: 'none',
+ backgroundColor: '$brushFill',
+})
diff --git a/components/style-panel/style-panel.tsx b/components/style-panel/style-panel.tsx
index 896031e6a..eee7d55ff 100644
--- a/components/style-panel/style-panel.tsx
+++ b/components/style-panel/style-panel.tsx
@@ -123,6 +123,7 @@ const StylePanelRoot = styled(motion(Panel.Root), {
alignItems: 'center',
pointerEvents: 'all',
padding: 2,
+ zIndex: 300,
'& hr': {
marginTop: 2,
diff --git a/components/tools-panel/shared.tsx b/components/tools-panel/shared.tsx
new file mode 100644
index 000000000..ed2f62b7d
--- /dev/null
+++ b/components/tools-panel/shared.tsx
@@ -0,0 +1,249 @@
+import Tooltip from 'components/tooltip'
+import styled from 'styles'
+
+export const ToolButton = styled('button', {
+ position: 'relative',
+ height: '32px',
+ width: '32px',
+ backgroundColor: '$panel',
+ borderRadius: '4px',
+ padding: '0',
+ margin: '0',
+ display: 'grid',
+ alignItems: 'center',
+ justifyContent: 'center',
+ outline: 'none',
+ border: 'none',
+ pointerEvents: 'all',
+ fontSize: '$0',
+ cursor: 'pointer',
+
+ '& > *': {
+ gridRow: 1,
+ gridColumn: 1,
+ },
+
+ '&:disabled': {
+ opacity: '0.5',
+ },
+
+ '& > span': {
+ width: '100%',
+ height: '100%',
+ display: 'flex',
+ alignItems: 'center',
+ },
+})
+
+export const PrimaryToolButton = styled(ToolButton, {
+ variants: {
+ bp: {
+ mobile: {
+ height: 44,
+ width: 44,
+ '& svg:nth-of-type(1)': {
+ height: '20px',
+ width: '20px',
+ },
+ },
+ small: {
+ '&:hover:not(:disabled)': {
+ backgroundColor: '$hover',
+ },
+ },
+ medium: {},
+ large: {},
+ },
+ isActive: {
+ true: {
+ color: '$selected',
+ },
+ },
+ },
+})
+
+export const SecondaryToolButton = styled(ToolButton, {
+ variants: {
+ bp: {
+ mobile: {
+ height: 44,
+ width: 44,
+ '& svg:nth-of-type(1)': {
+ height: '18px',
+ width: '18px',
+ },
+ },
+ small: {
+ '&:hover:not(:disabled)': {
+ backgroundColor: '$hover',
+ },
+ },
+ medium: {},
+ large: {},
+ },
+ isActive: {
+ true: {
+ color: '$selected',
+ },
+ },
+ },
+})
+
+export const TertiaryToolButton = styled(ToolButton, {
+ variants: {
+ bp: {
+ mobile: {
+ height: 32,
+ width: 44,
+ '& svg:nth-of-type(1)': {
+ height: '16px',
+ width: '16px',
+ },
+ },
+ small: {
+ height: 40,
+ width: 40,
+ '& svg:nth-of-type(1)': {
+ height: '18px',
+ width: '18px',
+ },
+ '&:hover:not(:disabled)': {
+ backgroundColor: '$hover',
+ },
+ },
+ medium: {},
+ large: {},
+ },
+ },
+})
+
+interface PrimaryToolButtonProps {
+ label: string
+ onClick: () => void
+ onDoubleClick?: () => void
+ isActive: boolean
+ children: React.ReactNode
+}
+
+export function PrimaryButton({
+ label,
+ onClick,
+ onDoubleClick,
+ isActive,
+ children,
+}: PrimaryToolButtonProps): JSX.Element {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+interface SecondaryToolButtonProps {
+ label: string
+ onClick: () => void
+ onDoubleClick?: () => void
+ isActive: boolean
+ children: React.ReactNode
+}
+
+export function SecondaryButton({
+ label,
+ onClick,
+ onDoubleClick,
+ isActive,
+ children,
+}: SecondaryToolButtonProps): JSX.Element {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+interface TertiaryToolProps {
+ label: string
+ onClick: () => void
+ onDoubleClick?: () => void
+ children: React.ReactNode
+}
+
+export function TertiaryButton({
+ label,
+ onClick,
+ onDoubleClick,
+ children,
+}: TertiaryToolProps): JSX.Element {
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export const Container = styled('div', {
+ backgroundColor: '$panel',
+ border: '1px solid $panel',
+ borderRadius: '4px',
+ boxShadow: '0px 2px 4px rgba(0,0,0,.16)',
+ display: 'flex',
+ height: 'fit-content',
+ padding: 2,
+ pointerEvents: 'all',
+ position: 'relative',
+ userSelect: 'none',
+ zIndex: 200,
+})
+
+export const TertiaryButtonsContainer = styled(Container, {
+ variants: {
+ bp: {
+ mobile: {
+ alignItems: 'center',
+ flexDirection: 'column',
+ },
+ small: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ },
+ },
+ },
+})
diff --git a/components/tools-panel/tools-panel.tsx b/components/tools-panel/tools-panel.tsx
index ed7a9ec06..943686ed1 100644
--- a/components/tools-panel/tools-panel.tsx
+++ b/components/tools-panel/tools-panel.tsx
@@ -5,18 +5,16 @@ import {
LockClosedIcon,
LockOpen1Icon,
Pencil1Icon,
- Pencil2Icon,
SquareIcon,
TextIcon,
} from '@radix-ui/react-icons'
-import { IconButton } from 'components/shared'
+import { PrimaryButton, SecondaryButton, Container } from './shared'
import React from 'react'
import state, { useSelector } from 'state'
import styled from 'styles'
import { ShapeType } from 'types'
import UndoRedo from './undo-redo'
import Zoom from './zoom'
-import Tooltip from '../tooltip'
const selectArrowTool = () => state.send('SELECTED_ARROW_TOOL')
const selectDrawTool = () => state.send('SELECTED_DRAW_TOOL')
@@ -24,167 +22,154 @@ const selectEllipseTool = () => state.send('SELECTED_ELLIPSE_TOOL')
const selectTextTool = () => state.send('SELECTED_TEXT_TOOL')
const selectRectangleTool = () => state.send('SELECTED_RECTANGLE_TOOL')
const selectSelectTool = () => state.send('SELECTED_SELECT_TOOL')
-const selectToolLock = () => state.send('TOGGLED_TOOL_LOCK')
+const toggleToolLock = () => state.send('TOGGLED_TOOL_LOCK')
export default function ToolsPanel(): JSX.Element {
const activeTool = useSelector((s) => s.data.activeTool)
const isToolLocked = useSelector((s) => s.data.settings.isToolLocked)
- const isPenLocked = useSelector((s) => s.data.settings.isPenLocked)
-
return (
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
- {isToolLocked ? : }
-
-
- {isPenLocked && (
-
-
-
-
-
- )}
+
+ {isToolLocked ? : }
+
-
-
-
+
+
+
)
}
-const OuterContainer = styled('div', {
+const ToolsPanelContainer = styled('div', {
position: 'fixed',
bottom: 44,
left: 0,
right: 0,
- padding: '0 8px 12px 8px',
width: '100%',
- display: 'flex',
+ minWidth: 0,
+ maxWidth: '100%',
+ display: 'grid',
+ gridTemplateColumns: '1fr auto 1fr',
+ padding: '0 8px 12px 8px',
alignItems: 'flex-end',
- justifyContent: 'center',
- flexWrap: 'wrap',
- gap: 16,
zIndex: 200,
+ gap: 12,
})
-const Flex = styled('div', {
+const CenterWrap = styled('div', {
+ gridRow: 1,
+ gridColumn: 2,
display: 'flex',
- width: '100%',
- padding: '0 4px',
- justifyContent: 'space-between',
- alignItems: 'flex-end',
+ width: 'fit-content',
+ justifyContent: 'center',
+})
+const LeftWrap = styled('div', {
+ gridRow: 1,
+ gridColumn: 1,
+ display: 'flex',
variants: {
size: {
+ mobile: {
+ flexDirection: 'column',
+ justifyContent: 'flex-end',
+ alignItems: 'flex-start',
+ '& > *:nth-of-type(1)': {
+ marginBottom: '8px',
+ },
+ },
small: {
- width: 'auto',
- padding: '0',
- justifyContent: 'center',
- '& > *:nth-child(n+2)': {
- marginLeft: 16,
+ flexDirection: 'row',
+ alignItems: 'flex-end',
+ justifyContent: 'space-between',
+ '& > *:nth-of-type(1)': {
+ marginBottom: '0px',
},
},
},
},
})
-const Container = styled('div', {
- position: 'relative',
- backgroundColor: '$panel',
- borderRadius: '4px',
- overflow: 'hidden',
- border: '1px solid $panel',
- pointerEvents: 'all',
- userSelect: 'none',
- height: '100%',
+const RightWrap = styled('div', {
+ gridRow: 1,
+ gridColumn: 3,
display: 'flex',
- padding: 4,
- boxShadow: '0px 2px 4px rgba(0,0,0,.12)',
-
- '& svg': {
- strokeWidth: 0,
+ variants: {
+ size: {
+ mobile: {
+ flexDirection: 'column-reverse',
+ justifyContent: 'flex-end',
+ alignItems: 'flex-end',
+ '& > *:nth-of-type(2)': {
+ marginBottom: '8px',
+ },
+ },
+ small: {
+ flexDirection: 'row',
+ alignItems: 'flex-end',
+ justifyContent: 'space-between',
+ '& > *:nth-of-type(2)': {
+ marginBottom: '0px',
+ },
+ },
+ },
},
})
diff --git a/components/tools-panel/undo-redo.tsx b/components/tools-panel/undo-redo.tsx
index 836b25974..177ef24eb 100644
--- a/components/tools-panel/undo-redo.tsx
+++ b/components/tools-panel/undo-redo.tsx
@@ -1,8 +1,6 @@
-import { IconButton } from 'components/shared'
-import { RotateCcw, RotateCw, Trash2 } from 'react-feather'
+import { TertiaryButton, TertiaryButtonsContainer } from './shared'
+import { Undo, Redo, Trash } from 'components/icons'
import state from 'state'
-import styled from 'styles'
-import Tooltip from '../tooltip'
const undo = () => state.send('UNDO')
const redo = () => state.send('REDO')
@@ -10,55 +8,16 @@ const clear = () => state.send('CLEARED_PAGE')
export default function UndoRedo(): JSX.Element {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
)
}
-
-const Container = styled('div', {
- position: 'absolute',
- bottom: 64,
- right: 12,
- backgroundColor: '$panel',
- borderRadius: '4px',
- overflow: 'hidden',
- alignSelf: 'flex-end',
- pointerEvents: 'all',
- userSelect: 'none',
- zIndex: 200,
- border: '1px solid $panel',
- boxShadow: '0px 2px 4px rgba(0,0,0,.12)',
- display: 'flex',
- padding: 4,
- flexDirection: 'column',
-
- '& svg': {
- height: 13,
- width: 13,
- },
-
- variants: {
- size: {
- small: {
- bottom: 12,
- flexDirection: 'row',
- alignItems: 'center',
- },
- },
- },
-})
diff --git a/components/tools-panel/zoom.tsx b/components/tools-panel/zoom.tsx
index 94ef58531..00c03b613 100644
--- a/components/tools-panel/zoom.tsx
+++ b/components/tools-panel/zoom.tsx
@@ -1,8 +1,6 @@
import { ZoomInIcon, ZoomOutIcon } from '@radix-ui/react-icons'
-import { IconButton } from 'components/shared'
+import { TertiaryButton, TertiaryButtonsContainer } from './shared'
import state, { useSelector } from 'state'
-import styled from 'styles'
-import Tooltip from '../tooltip'
import tld from 'utils/tld'
const zoomIn = () => state.send('ZOOMED_IN')
@@ -12,21 +10,15 @@ const zoomToActual = () => state.send('ZOOMED_TO_ACTUAL')
export default function Zoom(): JSX.Element {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
)
}
@@ -34,50 +26,12 @@ function ZoomCounter() {
const zoom = useSelector((s) => tld.getCurrentCamera(s.data).zoom)
return (
-
{Math.round(zoom * 100)}%
-
+
)
}
-
-const ZoomButton = styled(IconButton, {
- fontSize: '$0',
- padding: 8,
-})
-
-const Container = styled('div', {
- position: 'absolute',
- left: 12,
- bottom: 64,
- backgroundColor: '$panel',
- borderRadius: '4px',
- overflow: 'hidden',
- alignSelf: 'flex-end',
- pointerEvents: 'all',
- userSelect: 'none',
- zIndex: 200,
- border: '1px solid $panel',
- boxShadow: '0px 2px 4px rgba(0,0,0,.12)',
- display: 'flex',
- padding: 4,
- flexDirection: 'column',
- alignItems: 'center',
-
- '& svg': {
- strokeWidth: 0,
- },
-
- variants: {
- size: {
- small: {
- bottom: 12,
- flexDirection: 'row',
- alignItems: 'center',
- },
- },
- },
-})
diff --git a/hooks/useCanvasEvents.ts b/hooks/useCanvasEvents.ts
index 55aca9fbb..4ceed8d36 100644
--- a/hooks/useCanvasEvents.ts
+++ b/hooks/useCanvasEvents.ts
@@ -8,8 +8,13 @@ import {
fastTranslate,
} from 'state/hacks'
import inputs from 'state/inputs'
+import { isMobile } from 'utils'
import Vec from 'utils/vec'
+function handleFocusOut() {
+ state.send('BLURRED_EDITING_SHAPE')
+}
+
export default function useCanvasEvents(
rCanvas: MutableRefObject
) {
@@ -76,14 +81,12 @@ export default function useCanvasEvents(
// Send event on iOS when a user presses the "Done" key while editing a text element
useEffect(() => {
- function handleFocusOut() {
- state.send('BLURRED_EDITING_SHAPE')
- }
+ if (isMobile()) {
+ document.addEventListener('focusout', handleFocusOut)
- document.addEventListener('focusout', handleFocusOut)
-
- return () => {
- document.removeEventListener('focusout', handleFocusOut)
+ return () => {
+ document.removeEventListener('focusout', handleFocusOut)
+ }
}
}, [])
diff --git a/hooks/useLoadOnMount.ts b/hooks/useLoadOnMount.ts
index 11764506d..094278b98 100644
--- a/hooks/useLoadOnMount.ts
+++ b/hooks/useLoadOnMount.ts
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { useEffect } from 'react'
import state from 'state'
-import coopState from 'state/coop/coop-state'
+// import coopState from 'state/coop/coop-state'
export default function useLoadOnMount(roomId?: string) {
useEffect(() => {
@@ -21,7 +21,7 @@ export default function useLoadOnMount(roomId?: string) {
return () => {
state.send('UNMOUNTED', { roomId })
- coopState.send('LEFT_ROOM', { id: roomId })
+ // coopState.send('LEFT_ROOM', { id: roomId })
}
}, [roomId])
}
diff --git a/public/icons/Redo.svg b/public/icons/Redo.svg
new file mode 100644
index 000000000..b524e86eb
--- /dev/null
+++ b/public/icons/Redo.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/icons/Trash.svg b/public/icons/Trash.svg
new file mode 100644
index 000000000..aed40eb98
--- /dev/null
+++ b/public/icons/Trash.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/icons/Undo.svg b/public/icons/Undo.svg
new file mode 100644
index 000000000..c47375398
--- /dev/null
+++ b/public/icons/Undo.svg
@@ -0,0 +1,4 @@
+
diff --git a/state/state.ts b/state/state.ts
index 0bad830ab..3b555febf 100644
--- a/state/state.ts
+++ b/state/state.ts
@@ -734,7 +734,6 @@ const state = createState({
do: 'breakSession',
to: 'pinching.toolPinching',
},
- TOGGLED_TOOL_LOCK: 'toggleToolLock',
},
states: {
draw: {