diff --git a/src/electron/electron/core.cljs b/src/electron/electron/core.cljs index fdf252e93b6..521dd2e7caa 100644 --- a/src/electron/electron/core.cljs +++ b/src/electron/electron/core.cljs @@ -207,6 +207,10 @@ {:role "about" :label "About Logseq" :click about-fn}]})) + ;; Enable Cmd/Ctrl+= Zoom In + template (conj template + {:role "zoomin" + :accelerator "CommandOrControl+="}) menu (.buildFromTemplate Menu (clj->js template))] (.setApplicationMenu Menu menu))) diff --git a/src/main/frontend/components/container.css b/src/main/frontend/components/container.css index ccce10ffbcb..09b5c2c90cd 100644 --- a/src/main/frontend/components/container.css +++ b/src/main/frontend/components/container.css @@ -524,7 +524,7 @@ html[data-theme='dark'] { } &-btn { - @apply fixed bottom-4 right-8; + @apply fixed bottom-4 right-4 sm:right-8; > .inner { @apply font-bold diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index e551f2227b9..141682a7a06 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -411,16 +411,6 @@ right-sidebar? (:ui/sidebar-open? @state/state) editing-key (first (keys (:editor/editing? @state/state))) *el (rum/use-ref nil) - _ (rum/use-effect! (fn [] - (when-let [^js/HTMLElement cnt - (and right-sidebar? editing-key - (js/document.querySelector "#main-content-container"))] - (when (.contains cnt (js/document.querySelector (str "#" editing-key))) - (let [el (rum/deref *el) - ofx (- (.-scrollWidth cnt) (.-clientWidth cnt))] - (when (> ofx 0) - (set! (.-transform (.-style el)) (str "translateX(-" (+ ofx 20) "px)"))))))) - [right-sidebar? editing-key]) y-overflow-vh? (or (< to-max-height Y-BOUNDARY-HEIGHT) (> (- max-height' to-max-height) Y-BOUNDARY-HEIGHT)) to-max-height (if y-overflow-vh? max-height' to-max-height) @@ -430,22 +420,36 @@ style (merge {:top (+ top offset-top (if (int? y-diff) y-diff 0)) :max-height to-max-height - :max-width 700 + :max-width 700 ;; TODO: auto responsive fixed size - :width "fit-content" + :width "fit-content" :z-index 11} (when set-default-width? {:width max-width}) (if (<= vw-max-width (+ left (if set-default-width? max-width 500))) {:right 0} - {:left (if (or (nil? y-diff) (and y-diff (= y-diff 0))) left 0)}))] + {:left 0}))] + + (rum/use-effect! + (fn [] + (when-let [^js/HTMLElement cnt + (and right-sidebar? editing-key + (js/document.querySelector "#main-content-container"))] + (when (.contains cnt (js/document.querySelector (str "#" editing-key))) + (let [el (rum/deref *el) + ofx (- (.-scrollWidth cnt) (.-clientWidth cnt))] + (when (> ofx 0) + (set! (.-transform (.-style el)) + (util/format "translate(-%spx, %s)" (+ ofx 20) (if y-overflow-vh? "calc(-100% - 2rem)" 0)))))))) + [right-sidebar? editing-key y-overflow-vh?]) + [:div.absolute.rounded-md.shadow-lg.absolute-modal - {:ref *el + {:ref *el :data-modal-name modal-name - :class (if y-overflow-vh? "is-overflow-vh-y" "") - :on-mouse-down (fn [e] - (.stopPropagation e)) - :style style} + :class (if y-overflow-vh? "is-overflow-vh-y" "") + :on-mouse-down (fn [e] + (.stopPropagation e)) + :style style} cp])) (rum/defc transition-cp < rum/reactive diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 030faa6e1aa..1670ed593d5 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -2,14 +2,14 @@ (:require ["/frontend/utils" :as utils] [clojure.string :as string] [frontend.components.block :as component-block] - [frontend.components.query :as query] [frontend.components.content :as content] [frontend.components.editor :as editor] [frontend.components.hierarchy :as hierarchy] [frontend.components.plugins :as plugins] + [frontend.components.query :as query] [frontend.components.reference :as reference] - [frontend.components.svg :as svg] [frontend.components.scheduled-deadlines :as scheduled] + [frontend.components.svg :as svg] [frontend.config :as config] [frontend.context.i18n :refer [t]] [frontend.date :as date] @@ -21,6 +21,7 @@ [frontend.format.block :as block] [frontend.handler.common :as common-handler] [frontend.handler.config :as config-handler] + [frontend.handler.dnd :as dnd] [frontend.handler.editor :as editor-handler] [frontend.handler.graph :as graph-handler] [frontend.handler.notification :as notification] @@ -34,12 +35,13 @@ [frontend.util :as util] [frontend.util.text :as text-util] [goog.object :as gobj] + [logseq.graph-parser.mldoc :as gp-mldoc] [logseq.graph-parser.util :as gp-util] + [logseq.graph-parser.util.page-ref :as page-ref] [medley.core :as medley] + [promesa.core :as p] [reitit.frontend.easy :as rfe] - [rum.core :as rum] - [logseq.graph-parser.util.page-ref :as page-ref] - [logseq.graph-parser.mldoc :as gp-mldoc])) + [rum.core :as rum])) (defn- get-page-name [state] @@ -109,10 +111,26 @@ (rum/defc dummy-block [page-name] - (let [handler-fn (fn [] - (let [block (editor-handler/insert-first-page-block-if-not-exists! page-name {:redirect? false})] - (js/setTimeout #(editor-handler/edit-block! block :max (:block/uuid block)) 0)))] - [:div.ls-block.flex-1.flex-col.rounded-sm {:style {:width "100%"}} + (let [[hover set-hover!] (rum/use-state false) + click-handler-fn (fn [] + (let [block (editor-handler/insert-first-page-block-if-not-exists! page-name {:redirect? false})] + (js/setTimeout #(editor-handler/edit-block! block :max (:block/uuid block)) 0))) + drop-handler-fn (fn [^js event] + (util/stop event) + (p/let [block-uuids (state/get-selection-block-ids) + lookup-refs (map (fn [id] [:block/uuid id]) block-uuids) + selected (db/pull-many (state/get-current-repo) '[*] lookup-refs) + blocks (if (seq selected) selected [@component-block/*dragging-block]) + _ (editor-handler/insert-first-page-block-if-not-exists! page-name {:redirect? false})] + (js/setTimeout #(let [target-block (db/pull (:db/id (db/get-page page-name)))] + (dnd/move-blocks event blocks target-block :sibling)) + 0)))] + [:div.ls-block.flex-1.flex-col.rounded-sm + {:style {:width "100%" + ;; The same as .dnd-separator + :border-top (if hover + "3px solid #ccc" + nil)}} [:div.flex.flex-row [:div.flex.flex-row.items-center.mr-2.ml-1 {:style {:height 24}} [:span.bullet-container.cursor @@ -120,8 +138,12 @@ [:div.flex.flex-1 {:tabIndex 0 :on-key-press (fn [e] (when (= "Enter" (util/ekey e)) - (handler-fn))) - :on-click handler-fn} + (click-handler-fn))) + :on-click click-handler-fn + :on-drag-enter #(set-hover! true) + :on-drag-over #(util/stop %) + :on-drop drop-handler-fn + :on-drag-leave #(set-hover! false)} [:span.opacity-70 "Click here to edit..."]]]])) diff --git a/src/main/frontend/components/whiteboard.css b/src/main/frontend/components/whiteboard.css index e6f6184ab36..51427384b4f 100644 --- a/src/main/frontend/components/whiteboard.css +++ b/src/main/frontend/components/whiteboard.css @@ -205,7 +205,7 @@ input.tl-text-input { .tl-action-bar { left: 0.5rem; - bottom: 0.5rem; + bottom: 0; } .tl-primary-tools { diff --git a/src/main/frontend/handler/dnd.cljs b/src/main/frontend/handler/dnd.cljs index 40444e7e659..3bf8f2b801f 100644 --- a/src/main/frontend/handler/dnd.cljs +++ b/src/main/frontend/handler/dnd.cljs @@ -1,5 +1,5 @@ (ns frontend.handler.dnd - "Provides fns for drag n drop" + "Provides fns for drag and drop" (:require [frontend.handler.editor :as editor-handler] [frontend.handler.editor.property :as editor-property] [frontend.modules.outliner.core :as outliner-core] diff --git a/src/resources/dicts/en.edn b/src/resources/dicts/en.edn index 9a6eacf75e6..42d7421c198 100644 --- a/src/resources/dicts/en.edn +++ b/src/resources/dicts/en.edn @@ -465,6 +465,7 @@ :whiteboard/dashboard-card-edited "Edited " :whiteboard/toggle-grid "Toggle grid" :whiteboard/snap-to-grid "Snap to grid" + :whiteboard/toggle-pen-mode "Toggle pen mode" :flashcards/modal-welcome-title "Time to create a card!" :flashcards/modal-welcome-desc-1 "You can add \"#card\" to any block to turn it into a card or trigger \"/cloze\" to add some clozes." :flashcards/modal-welcome-desc-2 "You can " diff --git a/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx b/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx index 430783b6a08..4183dc50e0a 100644 --- a/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx @@ -41,10 +41,14 @@ export const ActionBar = observer(function ActionBar(): JSX.Element { app.api.toggleSnapToGrid() }, [app]) + const togglePenMode = React.useCallback(() => { + app.api.togglePenMode() + }, [app]) + return (
{!app.readOnly && ( -
+
@@ -54,7 +58,7 @@ export const ActionBar = observer(function ActionBar(): JSX.Element {
)} -
+
@@ -65,7 +69,7 @@ export const ActionBar = observer(function ActionBar(): JSX.Element {
-
+
)}
+ + {!app.readOnly && ( +
+ + + +
+ )}
) }) diff --git a/tldraw/apps/tldraw-logseq/src/styles.css b/tldraw/apps/tldraw-logseq/src/styles.css index 61553f6f47d..0f91cc68a49 100644 --- a/tldraw/apps/tldraw-logseq/src/styles.css +++ b/tldraw/apps/tldraw-logseq/src/styles.css @@ -166,7 +166,7 @@ html[data-theme='light'] { } .tl-action-bar { - @apply absolute bottom-0 flex items-center border-0 left-10 bottom-10; + @apply absolute flex items-center border-0 left-10 bottom-8 flex-wrap-reverse pr-12; z-index: 100000; user-select: none; diff --git a/tldraw/packages/core/src/lib/TLApi/TLApi.ts b/tldraw/packages/core/src/lib/TLApi/TLApi.ts index 3b6989fb05c..ab8bd2e4f9a 100644 --- a/tldraw/packages/core/src/lib/TLApi/TLApi.ts +++ b/tldraw/packages/core/src/lib/TLApi/TLApi.ts @@ -178,6 +178,13 @@ export class TLApi { + const { settings } = this.app + settings.update({ penMode: !settings.penMode }) + return this + } + setColor = (color: string): this => { const { settings } = this.app diff --git a/tldraw/packages/core/src/lib/TLSettings.ts b/tldraw/packages/core/src/lib/TLSettings.ts index c6383ef6f8f..2757a4d5a15 100644 --- a/tldraw/packages/core/src/lib/TLSettings.ts +++ b/tldraw/packages/core/src/lib/TLSettings.ts @@ -4,6 +4,7 @@ import { observable, makeObservable, action } from 'mobx' export interface TLSettingsProps { mode: 'light' | 'dark' showGrid: boolean + penMode: boolean snapToGrid: boolean color: string scaleLevel: string @@ -17,6 +18,7 @@ export class TLSettings implements TLSettingsProps { @observable mode: 'dark' | 'light' = 'light' @observable showGrid = true @observable snapToGrid = true + @observable penMode = false @observable scaleLevel = 'md' @observable color = '' diff --git a/tldraw/packages/react/src/components/AppCanvas.tsx b/tldraw/packages/react/src/components/AppCanvas.tsx index 91940c94084..76a43027130 100644 --- a/tldraw/packages/react/src/components/AppCanvas.tsx +++ b/tldraw/packages/react/src/components/AppCanvas.tsx @@ -27,6 +27,7 @@ export const AppCanvas = observer(function InnerApp( shapes={app.shapes} // TODO: use shapes in viewport later? assets={app.assets} showGrid={app.settings.showGrid} + penMode={app.settings.penMode} showSelection={app.showSelection} showSelectionRotation={app.showSelectionRotation} showResizeHandles={app.showResizeHandles} diff --git a/tldraw/packages/react/src/components/Canvas/Canvas.tsx b/tldraw/packages/react/src/components/Canvas/Canvas.tsx index 5969563c624..0234b45dadf 100644 --- a/tldraw/packages/react/src/components/Canvas/Canvas.tsx +++ b/tldraw/packages/react/src/components/Canvas/Canvas.tsx @@ -58,6 +58,7 @@ export interface TLCanvasProps { cursorRotation: number selectionRotation: number onEditingEnd: () => void + penMode: boolean showGrid: boolean showSelection: boolean showHandles: boolean diff --git a/tldraw/packages/react/src/hooks/useCanvasEvents.ts b/tldraw/packages/react/src/hooks/useCanvasEvents.ts index 4fef6ee0ae4..5c596630883 100644 --- a/tldraw/packages/react/src/hooks/useCanvasEvents.ts +++ b/tldraw/packages/react/src/hooks/useCanvasEvents.ts @@ -13,11 +13,19 @@ export function useCanvasEvents() { const events = React.useMemo(() => { const onPointerMove: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e callbacks.onPointerMove?.({ type: TLTargetType.Canvas, order }, e) } const onPointerDown: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e if (!order) e.currentTarget?.setPointerCapture(e.pointerId) @@ -41,17 +49,29 @@ export function useCanvasEvents() { } const onPointerUp: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e if (!order) e.currentTarget?.releasePointerCapture(e.pointerId) callbacks.onPointerUp?.({ type: TLTargetType.Canvas, order }, e) } const onPointerEnter: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e callbacks.onPointerEnter?.({ type: TLTargetType.Canvas, order }, e) } const onPointerLeave: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e callbacks.onPointerLeave?.({ type: TLTargetType.Canvas, order }, e) } diff --git a/tldraw/packages/react/src/hooks/useShapeEvents.ts b/tldraw/packages/react/src/hooks/useShapeEvents.ts index 99e38e839d2..81aaaa450d0 100644 --- a/tldraw/packages/react/src/hooks/useShapeEvents.ts +++ b/tldraw/packages/react/src/hooks/useShapeEvents.ts @@ -1,23 +1,33 @@ import * as React from 'react' import { TLTargetType } from '@tldraw/core' +import { useApp } from './useApp' import { useRendererContext } from '.' import { DOUBLE_CLICK_DURATION } from '../constants' import type { TLReactShape } from '../lib' import type { TLReactCustomEvents } from '../types' export function useShapeEvents(shape: S) { + const app = useApp() const { inputs, callbacks } = useRendererContext() const rDoubleClickTimer = React.useRef(-1) const events = React.useMemo(() => { const onPointerMove: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e callbacks.onPointerMove?.({ type: TLTargetType.Shape, shape, order }, e) e.order = order + 1 } const onPointerDown: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e if (!order) e.currentTarget?.setPointerCapture(e.pointerId) callbacks.onPointerDown?.({ type: TLTargetType.Shape, shape, order }, e) @@ -25,6 +35,10 @@ export function useShapeEvents(shape: S) { } const onPointerUp: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e if (!order) e.currentTarget?.releasePointerCapture(e.pointerId) callbacks.onPointerUp?.({ type: TLTargetType.Shape, shape, order }, e) @@ -42,12 +56,20 @@ export function useShapeEvents(shape: S) { } const onPointerEnter: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e callbacks.onPointerEnter?.({ type: TLTargetType.Shape, shape, order }, e) e.order = order + 1 } const onPointerLeave: TLReactCustomEvents['pointer'] = e => { + if (app.settings.penMode && (e.pointerType !== 'pen' || !e.isPrimary)) { + return + } + const { order = 0 } = e callbacks.onPointerLeave?.({ type: TLTargetType.Shape, shape, order }, e) e.order = order + 1