Procházet zdrojové kódy

wip: context bar action

Peng Xiao před 3 roky
rodič
revize
b3d69ec100

+ 16 - 97
tldraw/apps/tldraw-logseq/src/components/ContextBar/ContextBar.tsx

@@ -1,58 +1,19 @@
-import * as React from 'react'
 import {
+  getContextBarTranslation,
   HTMLContainer,
   TLContextBarComponent,
   useApp,
-  getContextBarTranslation,
 } from '@tldraw/react'
 import { observer } from 'mobx-react-lite'
-import type { TextShape, Shape } from '~lib/shapes'
-import { NumberInput } from '~components/inputs/NumberInput'
-import { ColorInput } from '~components/inputs/ColorInput'
-import { SwitchInput } from '../inputs/SwitchInput'
+import * as React from 'react'
+import type { Shape } from '~lib/shapes'
+import { getContextBarActionsForTypes } from './contextBarActionFactory'
 
 const _ContextBar: TLContextBarComponent<Shape> = ({ shapes, offsets, hidden }) => {
   const app = useApp()
   const rSize = React.useRef<[number, number] | null>(null)
   const rContextBar = React.useRef<HTMLDivElement>(null)
 
-  const updateStroke = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(e => {
-    shapes.forEach(shape => shape.update({ stroke: e.currentTarget.value }))
-    app.persist()
-  }, [])
-
-  const updateFill = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(e => {
-    shapes.forEach(shape => shape.update({ fill: e.currentTarget.value }))
-    app.persist()
-  }, [])
-
-  const updateStrokeWidth = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(e => {
-    shapes.forEach(shape => shape.update({ strokeWidth: +e.currentTarget.value }))
-    app.persist()
-  }, [])
-
-  const updateOpacity = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(e => {
-    shapes.forEach(shape => shape.update({ opacity: +e.currentTarget.value }))
-    app.persist()
-  }, [])
-
-  const updateFontSize = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(e => {
-    textShapes.forEach(shape => shape.update({ fontSize: +e.currentTarget.value }))
-    app.persist()
-  }, [])
-
-  const updateFontWeight = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>(e => {
-    textShapes.forEach(shape => shape.update({ fontWeight: +e.currentTarget.value }))
-    app.persist()
-  }, [])
-
-  const updateTransparent = React.useCallback(transparent => {
-    // const transparent = shapes.some(s => s.props.fill !== 'transparent')
-    console.log(transparent)
-    shapes.forEach(shape => shape.update({ fill: transparent ? 'transparent' : '#fff' }))
-    app.persist()
-  }, [])
-
   React.useLayoutEffect(() => {
     setTimeout(() => {
       const elm = rContextBar.current
@@ -72,63 +33,21 @@ const _ContextBar: TLContextBarComponent<Shape> = ({ shapes, offsets, hidden })
 
   if (!app) return null
 
-  const textShapes = shapes.filter(shape => shape.type === 'text') as TextShape[]
-  const ShapeContent =
-    shapes.length === 1 && 'ReactContextBar' in shapes[0] ? shapes[0]['ReactContextBar'] : null
-  const transparent = shapes.every(s => s.props.fill === 'transparent')
+  const Actions = getContextBarActionsForTypes(shapes.map(s => s.props.type))
 
   return (
     <HTMLContainer centered>
-      <div
-        ref={rContextBar}
-        className="tl-contextbar"
-        style={{ pointerEvents: hidden ? 'none' : 'all' }}
-      >
-        {ShapeContent ? (
-          <ShapeContent />
-        ) : (
-          <>
-            <ColorInput label="Stroke" value={shapes[0].props.stroke} onChange={updateStroke} />
-            {!transparent && (
-              <ColorInput label="Fill" value={shapes[0].props.fill} onChange={updateFill} />
-            )}
-            <SwitchInput
-              label="Transparent"
-              checked={transparent}
-              onCheckedChange={updateTransparent}
-            />
-            <NumberInput
-              label="Width"
-              value={Math.max(...shapes.map(shape => shape.props.strokeWidth))}
-              onChange={updateStrokeWidth}
-              style={{ width: 48 }}
-            />
-            <NumberInput
-              label="Opacity"
-              value={Math.max(...shapes.map(shape => shape.props.opacity))}
-              onChange={updateOpacity}
-              step={0.1}
-              style={{ width: 48 }}
-            />
-            {textShapes.length > 0 ? (
-              <>
-                <NumberInput
-                  label="Size"
-                  value={Math.max(...textShapes.map(shape => shape.props.fontSize))}
-                  onChange={updateFontSize}
-                  style={{ width: 48 }}
-                />
-                <NumberInput
-                  label=" Weight"
-                  value={Math.max(...textShapes.map(shape => shape.props.fontWeight))}
-                  onChange={updateFontWeight}
-                  style={{ width: 48 }}
-                />
-              </>
-            ) : null}
-          </>
-        )}
-      </div>
+      {Actions.length > 0 && (
+        <div
+          ref={rContextBar}
+          className="tl-contextbar"
+          style={{ pointerEvents: hidden ? 'none' : 'all' }}
+        >
+          {Actions.map((Action, idx) => (
+            <Action key={idx} />
+          ))}
+        </div>
+      )}
     </HTMLContainer>
   )
 }

+ 78 - 0
tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx

@@ -0,0 +1,78 @@
+import { isNonNullable } from '@tldraw/core'
+import { useApp } from '@tldraw/react'
+import { observer } from 'mobx-react-lite'
+import { TablerIcon } from '~components/icons'
+import { SelectInput, SelectOption } from '~components/inputs/SelectInput'
+import { LogseqPortalShape, Shape } from '~lib'
+
+export const contextBarActionTypes = [
+  'NoFill',
+  'LogseqPortalViewMode',
+  'ScaleLevel',
+  'ColorAccent',
+  'StrokeColor',
+  'NoStroke',
+  'OpenPage',
+  'OpenInRightSidebar',
+] as const
+
+type ContextBarActionType = typeof contextBarActionTypes[number]
+
+const contextBarActionMapping = new Map<ContextBarActionType, React.FC>()
+
+const LogseqPortalViewModeAction = observer(() => {
+  const app = useApp<Shape>()
+  const shapes = app.selectedShapesArray.filter(
+    s => s.props.type === LogseqPortalShape.defaultProps.type
+  ) as LogseqPortalShape[]
+
+  const collapsed = shapes.every(s => s.collapsed)
+  const ViewModeOptions: SelectOption[] = [
+    {
+      value: '0',
+      label: <TablerIcon name="layout-navbar-expand" />,
+    },
+    {
+      value: '1',
+      label: <TablerIcon name="layout-navbar-collapse" />,
+    },
+  ]
+  return (
+    <SelectInput
+      options={ViewModeOptions}
+      value={collapsed ? '1' : '0'}
+      onValueChange={v => {
+        shapes.forEach(shape => {
+          shape.setCollapsed(v === '1' ? true : false)
+        })
+      }}
+    />
+  )
+})
+
+contextBarActionMapping.set('LogseqPortalViewMode', LogseqPortalViewModeAction)
+
+type ShapeType = Shape['props']['type']
+
+const shapeMapping: Partial<Record<ShapeType, ContextBarActionType[]>> = {
+  'logseq-portal': ['LogseqPortalViewMode'],
+}
+
+export const getContextBarActionsForType = (type: ShapeType) => {
+  return (shapeMapping[type] ?? [])
+    .map(actionType => contextBarActionMapping.get(actionType))
+    .filter(isNonNullable)
+}
+
+export const getContextBarActionsForTypes = (types: ShapeType[]) => {
+  const actions = new Set(types.length > 0 ? getContextBarActionsForType(types[0]) : [])
+  for (let i = 1; i < types.length && actions.size > 0; i++) {
+    const actionsForType = getContextBarActionsForType(types[i])
+    actions.forEach(action => {
+      if (!actionsForType.includes(action)) {
+        actions.delete(action)
+      }
+    })
+  }
+  return Array.from(actions)
+}

+ 0 - 0
tldraw/apps/tldraw-logseq/src/components/inputs/ToggleGroupInput.tsx


+ 29 - 28
tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx

@@ -2,7 +2,7 @@
 import { TLBoxShape, TLBoxShapeProps, TLResizeInfo, validUUID } from '@tldraw/core'
 import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
 import Vec from '@tldraw/vec'
-import { makeObservable, runInAction } from 'mobx'
+import { action, computed, makeObservable, runInAction } from 'mobx'
 import { observer } from 'mobx-react-lite'
 import * as React from 'react'
 import { TablerIcon } from '~components/icons'
@@ -196,6 +196,32 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
     return false
   }
 
+  @computed get collapsed() {
+    return this.props.blockType === 'B' ? this.props.compact : this.props.collapsed
+  }
+
+  @action setCollapsed = (collapsed: boolean) => {
+    if (this.props.blockType === 'B') {
+      this.update({ compact: collapsed })
+      this.canResize[1] = !collapsed
+      if (!collapsed) {
+        // this will also persist the state, so we can skip persist call
+        this.autoResizeHeight()
+      } else {
+        this.persist?.()
+      }
+    } else {
+      const originalHeight = this.props.size[1]
+      this.canResize[1] = !collapsed
+      this.update({
+        collapsed: collapsed,
+        size: [this.props.size[0], collapsed ? HEADER_HEIGHT : this.props.collapsedHeight],
+        collapsedHeight: collapsed ? originalHeight : this.props.collapsedHeight,
+      })
+      this.persist?.()
+    }
+  }
+
   useComponentSize<T extends HTMLElement>(ref: React.RefObject<T> | null, selector = '') {
     const [size, setSize] = React.useState<[number, number]>([0, 0])
     const app = useApp<Shape>()
@@ -253,21 +279,7 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
           <SwitchInput
             label="Collapsed"
             checked={this.props.collapsed}
-            onCheckedChange={collapsing => {
-              runInAction(() => {
-                const originalHeight = this.props.size[1]
-                this.canResize[1] = !collapsing
-                this.update({
-                  collapsed: collapsing,
-                  size: [
-                    this.props.size[0],
-                    collapsing ? HEADER_HEIGHT : this.props.collapsedHeight,
-                  ],
-                  collapsedHeight: collapsing ? originalHeight : this.props.collapsedHeight,
-                })
-                app.persist()
-              })
-            }}
+            onCheckedChange={this.setCollapsed}
           />
         )}
 
@@ -275,18 +287,7 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
           <SwitchInput
             label="Compact"
             checked={this.props.compact}
-            onCheckedChange={compact => {
-              runInAction(() => {
-                this.update({ compact })
-                this.canResize[1] = !compact
-                if (!compact) {
-                  // this will also persist the state, so we can skip persist call
-                  this.autoResizeHeight()
-                } else {
-                  app.persist()
-                }
-              })
-            }}
+            onCheckedChange={this.setCollapsed}
           />
         )}
       </>