mirror of https://github.com/logseq/logseq
fix: enhance pan / overscroll check
parent
5dc06093ec
commit
6e5e686a52
|
@ -298,6 +298,7 @@
|
||||||
:route-match route-match})
|
:route-match route-match})
|
||||||
|
|
||||||
[:div#main-content-container.scrollbar-spacing.w-full.flex.justify-center.flex-row
|
[:div#main-content-container.scrollbar-spacing.w-full.flex.justify-center.flex-row
|
||||||
|
{:data-is-margin-less-pages margin-less-pages?}
|
||||||
|
|
||||||
[:div.cp__sidebar-main-content
|
[:div.cp__sidebar-main-content
|
||||||
{:data-is-margin-less-pages margin-less-pages?
|
{:data-is-margin-less-pages margin-less-pages?
|
||||||
|
|
|
@ -46,11 +46,15 @@
|
||||||
#main-content {
|
#main-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: calc(100vh - var(--ls-headbar-height));
|
height: calc(100vh - var(--ls-headbar-height));
|
||||||
|
}
|
||||||
|
|
||||||
&-container {
|
#main-content-container {
|
||||||
@apply p-4 sm:px-8;
|
@apply p-4 sm:px-8;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main-content-container[data-is-margin-less-pages=true] {
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-sidebar-inner {
|
.left-sidebar-inner {
|
||||||
|
|
|
@ -35,4 +35,7 @@
|
||||||
[state]
|
[state]
|
||||||
(let [name (get-whiteboard-name state)
|
(let [name (get-whiteboard-name state)
|
||||||
tldr-name (str "draws/" name ".tldr")]
|
tldr-name (str "draws/" name ".tldr")]
|
||||||
(tldraw-app {:file tldr-name})))
|
[:div.absolute.w-full.h-full
|
||||||
|
;; makes sure the whiteboard will not cover the borders
|
||||||
|
{:style {:padding "0.5px"}}
|
||||||
|
(tldraw-app {:file tldr-name})]))
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
.logseq-tldraw .tl-container {
|
||||||
|
background-color: var(--ls-secondary-background-color);
|
||||||
|
}
|
|
@ -24,22 +24,21 @@
|
||||||
[state data option]
|
[state data option]
|
||||||
(let [{:keys [file]} option]
|
(let [{:keys [file]} option]
|
||||||
(when file
|
(when file
|
||||||
[:div.overflow-hidden.draw.tldraw
|
[:div.draw.tldraw.relative.w-full.h-full
|
||||||
{:style {:overscroll-behavior "none"}}
|
{:style {:overscroll-behavior "none"}
|
||||||
[:div.draw-wrap.relative
|
:on-blur #(state/set-block-component-editing-mode! false)
|
||||||
{:on-blur #(state/set-block-component-editing-mode! false)
|
;; wheel -> overscroll may cause browser navigation
|
||||||
:on-wheel util/stop-propagation ;; wheel -> overscroll may cause browser navigation
|
:on-wheel util/stop-propagation}
|
||||||
:style {:height "calc(100vh - 80px)"}}
|
|
||||||
|
|
||||||
(tldraw {:PageComponent page
|
(tldraw {:PageComponent page
|
||||||
:searchHandler (comp clj->js vec search/page-search)
|
:searchHandler (comp clj->js vec search/page-search)
|
||||||
:onPersist (fn [app]
|
:onPersist (fn [app]
|
||||||
(let [document (gobj/get app "serialized")
|
(let [document (gobj/get app "serialized")
|
||||||
s (js/JSON.stringify document)]
|
s (js/JSON.stringify document)]
|
||||||
(draw-handler/save-draw! file s)))
|
(draw-handler/save-draw! file s)))
|
||||||
:model data
|
:model data
|
||||||
:onApp (fn [app]
|
:onApp (fn [app]
|
||||||
(state/set-state! [:ui/whiteboards (::id state)] app))})]])))
|
(state/set-state! [:ui/whiteboards (::id state)] app))})])))
|
||||||
|
|
||||||
(rum/defc tldraw-app
|
(rum/defc tldraw-app
|
||||||
[option]
|
[option]
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const AppUI = observer(function AppUI() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* <ToolBar /> */}
|
{/* <ToolBar /> */}
|
||||||
<StatusBar />
|
{/* <StatusBar /> */}
|
||||||
<PrimaryTools />
|
<PrimaryTools />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { useApp } from '@tldraw/react'
|
||||||
|
import { useGesture } from '@use-gesture/react'
|
||||||
|
import type { TLViewport } from '@tldraw/core'
|
||||||
|
|
||||||
|
function useSampling(fn: () => void, rate: number) {
|
||||||
|
React.useEffect(() => {
|
||||||
|
const interval = setInterval(fn, 1000 / rate)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [fn, rate])
|
||||||
|
}
|
||||||
|
|
||||||
|
function now() {
|
||||||
|
return new Date().getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCameraMovingRef(bias = 10, timeout = 1000) {
|
||||||
|
const app = useApp()
|
||||||
|
const movingRef = React.useRef<boolean>(false)
|
||||||
|
const prevCamera = React.useRef<TLViewport['camera']>()
|
||||||
|
const lastMovingRef = React.useRef<number>(now())
|
||||||
|
const sampleFn = React.useCallback(() => {
|
||||||
|
const { point, zoom } = app.viewport.camera
|
||||||
|
if (prevCamera.current) {
|
||||||
|
const { point: prevPoint } = prevCamera.current
|
||||||
|
const moving = Math.abs(point[0] - prevPoint[0]) + Math.abs(point[1] - prevPoint[1]) > bias
|
||||||
|
if (moving) {
|
||||||
|
movingRef.current = true
|
||||||
|
lastMovingRef.current = now()
|
||||||
|
} else if (now() - lastMovingRef.current > timeout) {
|
||||||
|
movingRef.current = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevCamera.current = {
|
||||||
|
point: [...point],
|
||||||
|
zoom,
|
||||||
|
}
|
||||||
|
}, [app])
|
||||||
|
|
||||||
|
useGesture(
|
||||||
|
{
|
||||||
|
// immediately set moving to false
|
||||||
|
onMouseDown: () => {
|
||||||
|
movingRef.current = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eventOptions: {
|
||||||
|
capture: true,
|
||||||
|
},
|
||||||
|
target: window
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
useSampling(sampleFn, 30)
|
||||||
|
return movingRef
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import { CustomStyleProps, withClampedStyles } from './style-props'
|
||||||
import { TextInput } from '~components/inputs/TextInput'
|
import { TextInput } from '~components/inputs/TextInput'
|
||||||
import { LogseqContext } from '~lib/logseq-context'
|
import { LogseqContext } from '~lib/logseq-context'
|
||||||
import type { Shape } from '~lib'
|
import type { Shape } from '~lib'
|
||||||
|
import { useCameraMovingRef } from '~hooks/useCameraMoving'
|
||||||
|
|
||||||
export interface LogseqPortalShapeProps extends TLBoxShapeProps, CustomStyleProps {
|
export interface LogseqPortalShapeProps extends TLBoxShapeProps, CustomStyleProps {
|
||||||
type: 'logseq-portal'
|
type: 'logseq-portal'
|
||||||
|
@ -100,17 +101,20 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
|
||||||
} = this
|
} = this
|
||||||
|
|
||||||
const app = useApp<Shape>()
|
const app = useApp<Shape>()
|
||||||
|
const isMoving = useCameraMovingRef()
|
||||||
const { Page } = React.useContext(LogseqContext)
|
const { Page } = React.useContext(LogseqContext)
|
||||||
const isSelected = app.selectedIds.has(this.id)
|
const isSelected = app.selectedIds.has(this.id)
|
||||||
const disableTlEvents = !isEditing && !isSelected && app.selectedTool.id !== 'select'
|
const enableTlEvents = () => {
|
||||||
|
return isMoving.current || isEditing || isSelected || app.selectedTool.id !== 'select'
|
||||||
|
}
|
||||||
|
|
||||||
const stop = React.useCallback(
|
const stop = React.useCallback(
|
||||||
e => {
|
e => {
|
||||||
if (!disableTlEvents) {
|
if (!enableTlEvents()) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[disableTlEvents]
|
[enableTlEvents]
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!Page) {
|
if (!Page) {
|
||||||
|
@ -147,7 +151,7 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
overscrollBehavior: 'none',
|
overscrollBehavior: 'none',
|
||||||
height: pageId ? 'calc(100% - 32px)' : '100%',
|
height: pageId ? 'calc(100% - 33px)' : '100%',
|
||||||
pointerEvents: isSelected ? 'none' : 'all',
|
pointerEvents: isSelected ? 'none' : 'all',
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
opacity: isSelected ? 0.5 : 1,
|
opacity: isSelected ? 0.5 : 1,
|
||||||
|
|
Loading…
Reference in New Issue