Skip to content

Commit

Permalink
Fix (Whiteboards): Portal height calculation bug (#9161)
Browse files Browse the repository at this point in the history
* fix: portal height

* fix: remove circle button from portals

* enhance: remove unnecessary dev tools

* enhance: convert collapse btn-group to toggle

* enhance: introduce collapse shortcut
  • Loading branch information
sprocketc committed Apr 24, 2023
1 parent 2b7355b commit 1aca903
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 263 deletions.
18 changes: 1 addition & 17 deletions tldraw/apps/tldraw-logseq/src/components/Button/CircleButton.tsx
@@ -1,11 +1,8 @@
import React from 'react'
import { TablerIcon } from '../icons'

export const CircleButton = ({
active,
style,
icon,
otherIcon,
onClick,
}: {
active?: boolean
Expand All @@ -14,27 +11,14 @@ export const CircleButton = ({
otherIcon?: string
onClick: () => void
}) => {
const [recentlyChanged, setRecentlyChanged] = React.useState(false)

React.useEffect(() => {
setRecentlyChanged(true)
const timer = setTimeout(() => {
setRecentlyChanged(false)
}, 500)
return () => clearTimeout(timer)
}, [active])

return (
<button
data-active={active}
data-recently-changed={recentlyChanged}
data-html2canvas-ignore="true"
style={style}
className="tl-circle-button"
onPointerDown={onClick}
>
<div className="tl-circle-button-icons-wrapper" data-icons-count={otherIcon ? 2 : 1}>
{otherIcon && <TablerIcon name={otherIcon} />}
<div className="tl-circle-button-icons-wrapper">
<TablerIcon name={icon} />
</div>
</button>
Expand Down
Expand Up @@ -33,7 +33,7 @@ import { LogseqContext } from '../../lib/logseq-context'

export const contextBarActionTypes = [
// Order matters
'Edit',
'LogseqPortalViewMode',
'Geometry',
'AutoResizing',
'Swatch',
Expand All @@ -44,14 +44,12 @@ export const contextBarActionTypes = [
'YoutubeLink',
'TwitterLink',
'IFrameSource',
'LogseqPortalViewMode',
'ArrowMode',
'Links',
] as const

type ContextBarActionType = typeof contextBarActionTypes[number]
const singleShapeActions: ContextBarActionType[] = [
'Edit',
'YoutubeLink',
'TwitterLink',
'IFrameSource',
Expand All @@ -65,7 +63,6 @@ type ShapeType = Shape['props']['type']
export const shapeMapping: Record<ShapeType, ContextBarActionType[]> = {
'logseq-portal': [
'Swatch',
'Edit',
'LogseqPortalViewMode',
'ScaleLevel',
'AutoResizing',
Expand All @@ -74,13 +71,13 @@ export const shapeMapping: Record<ShapeType, ContextBarActionType[]> = {
youtube: ['YoutubeLink', 'Links'],
tweet: ['TwitterLink', 'Links'],
iframe: ['IFrameSource', 'Links'],
box: ['Edit', 'Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
ellipse: ['Edit', 'Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
polygon: ['Edit', 'Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
line: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'ArrowMode', 'Links'],
box: ['Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
ellipse: ['Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
polygon: ['Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
line: ['TextStyle', 'Swatch', 'ScaleLevel', 'ArrowMode', 'Links'],
pencil: ['Swatch', 'Links', 'ScaleLevel'],
highlighter: ['Swatch', 'Links', 'ScaleLevel'],
text: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'AutoResizing', 'Links'],
text: ['TextStyle', 'Swatch', 'ScaleLevel', 'AutoResizing', 'Links'],
html: ['ScaleLevel', 'AutoResizing', 'Links'],
image: ['Links'],
video: ['Links'],
Expand All @@ -98,54 +95,6 @@ function filterShapeByAction<S extends Shape>(type: ContextBarActionType) {
return unlockedSelectedShapes.filter(shape => shapeMapping[shape.props.type]?.includes(type))
}

const EditAction = observer(() => {
const {
handlers: { isWhiteboardPage, redirectToPage, getRedirectPageName, insertFirstPageBlock },
} = React.useContext(LogseqContext)

const app = useApp<Shape>()
const shape = filterShapeByAction('Edit')[0]

const iconName =
('label' in shape.props && shape.props.label) || ('text' in shape.props && shape.props.text)
? 'forms'
: 'text'

return (
<Button
type="button"
tooltip="Edit"
onClick={() => {
app.api.editShape(shape)
if (shape.props.type === 'logseq-portal') {
let uuid = shape.props.pageId
if (shape.props.blockType === 'P') {
if (isWhiteboardPage(uuid)) {
redirectToPage(uuid)
}

const pageId = getRedirectPageName(shape.props.pageId)
let pageBlocksTree = window.logseq?.api?.get_page_blocks_tree?.(pageId)

if (pageBlocksTree?.length === 0) {
insertFirstPageBlock(pageId)
pageBlocksTree = window.logseq?.api?.get_page_blocks_tree?.(pageId)
}

const firstNonePropertyBlock =
pageBlocksTree?.find(b => !('propertiesOrder' in b)) || pageBlocksTree[0]

uuid = firstNonePropertyBlock?.uuid
}
window.logseq?.api?.edit_block?.(uuid)
}
}}
>
<TablerIcon name={iconName} />
</Button>
)
})

const AutoResizingAction = observer(() => {
const app = useApp<Shape>()
const shapes = filterShapeByAction<LogseqPortalShape | TextShape | HTMLShape>('AutoResizing')
Expand Down Expand Up @@ -181,30 +130,20 @@ const LogseqPortalViewModeAction = observer(() => {
const shapes = filterShapeByAction<LogseqPortalShape>('LogseqPortalViewMode')

const collapsed = shapes.every(s => s.collapsed)
const ViewModeOptions: ToggleGroupInputOption[] = [
{
value: '1',
icon: 'object-compact',
tooltip: 'Collapse',
},
{
value: '0',
icon: 'object-expanded',
tooltip: 'Expand',
},
]
if (!collapsed && !shapes.every(s => !s.collapsed)) {
return null
}

return (
<ToggleGroupInput
title="View Mode"
options={ViewModeOptions}
value={collapsed ? '1' : '0'}
onValueChange={v => {
shapes.forEach(shape => {
shape.toggleCollapsed()
})
app.persist()
}}
/>
<ToggleInput
tooltip={collapsed ? 'Expand' : 'Collapse'}
toggle={shapes.every(s => s.props.type === 'logseq-portal')}
className="tl-button"
pressed={collapsed}
onPressedChange={() => app.api.setCollapsed(!collapsed) }
>
<TablerIcon name={collapsed ? 'object-expanded' : 'object-compact'} />
</ToggleInput>
)
})

Expand Down Expand Up @@ -527,7 +466,6 @@ const LinksAction = observer(() => {
)
})

contextBarActionMapping.set('Edit', EditAction)
contextBarActionMapping.set('Geometry', GeometryAction)
contextBarActionMapping.set('AutoResizing', AutoResizingAction)
contextBarActionMapping.set('LogseqPortalViewMode', LogseqPortalViewModeAction)
Expand Down
63 changes: 1 addition & 62 deletions tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx
@@ -1,59 +1,12 @@
import { useApp, useRendererContext } from '@tldraw/react'
import { autorun } from 'mobx'
import { useRendererContext } from '@tldraw/react'
import { observer } from 'mobx-react-lite'
import React from 'react'
import ReactDOM from 'react-dom'
import type { Shape } from '../../lib'

const printPoint = (point: number[]) => {
return `[${point.map(d => d?.toFixed(2) ?? '-').join(', ')}]`
}

const HistoryStack = observer(function HistoryStack() {
const app = useApp<Shape>()
const anchorRef = React.useRef<HTMLDivElement>()
const [_, setTick] = React.useState(0)

React.useEffect(() => {
anchorRef.current = document.createElement('div')
anchorRef.current.style.display = 'contents'
document.body.append(anchorRef.current)
setTick(tick => tick + 1)
return () => {
anchorRef.current?.remove()
}
}, [])

React.useEffect(() => {
requestAnimationFrame(() => {
anchorRef.current
?.querySelector(`[data-item-index="${app.history.pointer}"]`)
?.scrollIntoView()
})
}, [app.history.pointer])

return anchorRef.current
? ReactDOM.createPortal(
<div className="fixed z-[1000] left-4 max-w-[400px] top-4 overflow-scroll bg-gray-200 flex gap-2 p-2">
{app.history.stack.map((item, i) => (
<div
data-item-index={i}
style={{
background: app.history.pointer === i ? 'pink' : 'grey',
}}
key={i}
onClick={() => app.history.setPointer(i)}
className="flex items-center rounded-lg px-2 h-[32px] whitespace-nowrap"
>
{item.pages[0].nonce}
</div>
))}
</div>,
anchorRef.current
)
: null
})

export const DevTools = observer(() => {
const {
viewport: {
Expand All @@ -63,13 +16,9 @@ export const DevTools = observer(() => {
inputs,
} = useRendererContext()

const canvasAnchorRef = React.useRef<HTMLElement | null>()
const statusbarAnchorRef = React.useRef<HTMLElement | null>()

React.useEffect(() => {
const canvasAnchor = document.getElementById('tl-dev-tools-canvas-anchor')
canvasAnchorRef.current = canvasAnchor

const statusbarAnchor = document.getElementById('tl-statusbar-anchor')
statusbarAnchorRef.current = statusbarAnchor
}, [])
Expand All @@ -84,15 +33,6 @@ export const DevTools = observer(() => {
.map(p => p.join(''))
.join('|')

const originPoint = canvasAnchorRef.current
? ReactDOM.createPortal(
<svg className="tl-renderer-dev-tools tl-grid">
<circle cx={point[0] * zoom} cy={point[1] * zoom} r="4" fill="red" />
</svg>,
canvasAnchorRef.current
)
: null

const rendererStatus = statusbarAnchorRef.current
? ReactDOM.createPortal(
<div
Expand All @@ -110,7 +50,6 @@ export const DevTools = observer(() => {

return (
<>
{originPoint}
{rendererStatus}
</>
)
Expand Down

0 comments on commit 1aca903

Please sign in to comment.