Jelajahi Sumber

feat: add scale option to shapes and arrows

Konstantinos Kaloutas 2 tahun lalu
induk
melakukan
5b1a323a06

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

@@ -63,10 +63,10 @@ export const shapeMapping: Record<ShapeType, ContextBarActionType[]> = {
   ],
   youtube: ['YoutubeLink', 'Links'],
   iframe: ['IFrameSource', 'Links'],
-  box: ['Edit', 'TextStyle', 'Swatch', 'NoFill', 'StrokeType', 'Links'],
-  ellipse: ['Edit', 'TextStyle', 'Swatch', 'NoFill', 'StrokeType', 'Links'],
-  polygon: ['Edit', 'TextStyle', 'Swatch', 'NoFill', 'StrokeType', 'Links'],
-  line: ['Edit', 'TextStyle', 'Swatch', 'ArrowMode', 'Links'],
+  box: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
+  ellipse: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
+  polygon: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
+  line: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'ArrowMode', 'Links'],
   pencil: ['Swatch', 'Links'],
   highlighter: ['Swatch', 'Links'],
   text: ['Edit', 'TextStyle', 'Swatch', 'ScaleLevel', 'AutoResizing', 'Links'],

+ 31 - 2
tldraw/apps/tldraw-logseq/src/lib/shapes/BoxShape.tsx

@@ -7,15 +7,29 @@ import { observer } from 'mobx-react-lite'
 import { CustomStyleProps, withClampedStyles } from './style-props'
 import { BindingIndicator } from './BindingIndicator'
 import { TextLabel } from './text/TextLabel'
+import type { SizeLevel } from '.'
+import { action, computed } from 'mobx'
+
 export interface BoxShapeProps extends TLBoxShapeProps, CustomStyleProps {
   borderRadius: number
   type: 'box'
   label: string
+  fontSize: number
   fontWeight: number
   italic: boolean
+  scaleLevel?: SizeLevel
 }
 
-const font = '18px / 1 var(--ls-font-family)'
+const font = '20px / 1 var(--ls-font-family)'
+
+const levelToScale = {
+  xs: 10,
+  sm: 16,
+  md: 20,
+  lg: 32,
+  xl: 48,
+  xxl: 60,
+}
 
 export class BoxShape extends TLBoxShape<BoxShapeProps> {
   static id = 'box'
@@ -31,6 +45,7 @@ export class BoxShape extends TLBoxShape<BoxShapeProps> {
     fill: '',
     noFill: false,
     fontWeight: 400,
+    fontSize: 20,
     italic: false,
     strokeType: 'line',
     strokeWidth: 2,
@@ -55,6 +70,7 @@ export class BoxShape extends TLBoxShape<BoxShapeProps> {
           label,
           italic,
           fontWeight,
+          fontSize,
         },
       } = this
 
@@ -62,7 +78,7 @@ export class BoxShape extends TLBoxShape<BoxShapeProps> {
         label || isEditing
           ? getTextLabelSize(
               label,
-              { fontFamily: 'var(--ls-font-family)', fontSize: 18, lineHeight: 1, fontWeight },
+              { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
               4
             )
           : [0, 0]
@@ -89,6 +105,7 @@ export class BoxShape extends TLBoxShape<BoxShapeProps> {
             color={getComputedColor(stroke, 'text')}
             offsetX={offset[0]}
             offsetY={offset[1]}
+            fontSize={fontSize}
             scale={scale}
             isEditing={isEditing}
             onChange={handleLabelChange}
@@ -127,6 +144,18 @@ export class BoxShape extends TLBoxShape<BoxShapeProps> {
     }
   )
 
+  @computed get scaleLevel() {
+    return this.props.scaleLevel ?? 'md'
+  }
+
+  @action setScaleLevel = async (v?: SizeLevel) => {
+    this.update({
+      scaleLevel: v,
+      fontSize: levelToScale[v ?? 'md'],
+    })
+    this.onResetBounds()
+  }
+
   ReactIndicator = observer(() => {
     const {
       props: {

+ 30 - 1
tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx

@@ -11,16 +11,30 @@ import * as React from 'react'
 import { observer } from 'mobx-react-lite'
 import { CustomStyleProps, withClampedStyles } from './style-props'
 import { TextLabel } from './text/TextLabel'
+import type { SizeLevel } from '.'
+import { action, computed } from 'mobx'
+
 export interface EllipseShapeProps extends TLEllipseShapeProps, CustomStyleProps {
   type: 'ellipse'
   size: number[]
   label: string
+  fontSize: number
   fontWeight: number
   italic: boolean
+  scaleLevel?: SizeLevel
 }
 
 const font = '18px / 1 var(--ls-font-family)'
 
+const levelToScale = {
+  xs: 10,
+  sm: 16,
+  md: 20,
+  lg: 32,
+  xl: 48,
+  xxl: 60,
+}
+
 export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
   static id = 'ellipse'
 
@@ -34,6 +48,7 @@ export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
     fill: '',
     noFill: false,
     fontWeight: 400,
+    fontSize: 20,
     italic: false,
     strokeType: 'line',
     strokeWidth: 2,
@@ -56,13 +71,14 @@ export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
         label,
         italic,
         fontWeight,
+        fontSize,
       } = this.props
 
       const labelSize =
         label || isEditing
           ? getTextLabelSize(
               label,
-              { fontFamily: 'var(--ls-font-family)', fontSize: 18, lineHeight: 1, fontWeight },
+              { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
               4
             )
           : [0, 0]
@@ -94,6 +110,7 @@ export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
             onChange={handleLabelChange}
             onBlur={onEditingEnd}
             fontStyle={italic ? 'italic' : 'normal'}
+            fontSize={fontSize}
             fontWeight={fontWeight}
             pointerEvents={!!label}
           />
@@ -121,6 +138,18 @@ export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
     }
   )
 
+  @computed get scaleLevel() {
+    return this.props.scaleLevel ?? 'md'
+  }
+
+  @action setScaleLevel = async (v?: SizeLevel) => {
+    this.update({
+      scaleLevel: v,
+      fontSize: levelToScale[v ?? 'md'],
+    })
+    this.onResetBounds()
+  }
+
   ReactIndicator = observer(() => {
     const {
       size: [w, h],

+ 49 - 3
tldraw/apps/tldraw-logseq/src/lib/shapes/LineShape.tsx

@@ -10,15 +10,28 @@ import { CustomStyleProps, withClampedStyles } from './style-props'
 import { getTextLabelSize } from '@tldraw/core'
 import { LabelMask } from './text/LabelMask'
 import { TextLabel } from './text/TextLabel'
+import type { SizeLevel } from '.'
+import { action, computed } from 'mobx'
 
 interface LineShapeProps extends CustomStyleProps, TLLineShapeProps {
   type: 'line'
   label: string
+  fontSize: number
   fontWeight: number
   italic: boolean
+  scaleLevel?: SizeLevel
 }
 
-const font = '18px / 1 var(--ls-font-family)'
+const font = '20px / 1 var(--ls-font-family)'
+
+const levelToScale = {
+  xs: 10,
+  sm: 16,
+  md: 20,
+  lg: 32,
+  xl: 48,
+  xxl: 60,
+}
 
 export class LineShape extends TLLineShape<LineShapeProps> {
   static id = 'line'
@@ -36,6 +49,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
     fill: '',
     noFill: true,
     fontWeight: 400,
+    fontSize: 20,
     italic: false,
     strokeType: 'line',
     strokeWidth: 1,
@@ -57,9 +71,17 @@ export class LineShape extends TLLineShape<LineShapeProps> {
       label,
       italic,
       fontWeight,
+      fontSize,
       id,
     } = this.props
-    const labelSize = label || isEditing ? getTextLabelSize(label, font, 6) : [0, 0]
+    const labelSize =
+    label || isEditing
+      ? getTextLabelSize(
+          label,
+          { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
+          6
+        )
+      : [0, 0]
     const midPoint = Vec.med(start.point, end.point)
     const dist = Vec.dist(start.point, end.point)
     const scale = Math.max(
@@ -81,6 +103,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
         <TextLabel
           font={font}
           text={label}
+          fontSize={fontSize}
           color={getComputedColor(stroke, 'text')}
           offsetX={offset[0]}
           offsetY={offset[1]}
@@ -102,16 +125,37 @@ export class LineShape extends TLLineShape<LineShapeProps> {
     )
   })
 
+  @computed get scaleLevel() {
+    return this.props.scaleLevel ?? 'md'
+  }
+
+  @action setScaleLevel = async (v?: SizeLevel) => {
+    this.update({
+      scaleLevel: v,
+      fontSize: levelToScale[v ?? 'md'],
+    })
+    this.onResetBounds()
+  }
+
   ReactIndicator = observer(({ isEditing }: TLComponentProps) => {
     const {
       id,
       decorations,
       label,
       strokeWidth,
+      fontSize,
+      fontWeight,
       handles: { start, end },
     } = this.props
     const bounds = this.getBounds()
-    const labelSize = label ? getTextLabelSize(label, font, 6) : [0, 0]
+    const labelSize =
+    label || isEditing
+      ? getTextLabelSize(
+          label,
+          { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
+          6
+        )
+      : [0, 0]
     const midPoint = Vec.med(start.point, end.point)
     const dist = Vec.dist(start.point, end.point)
     const scale = Math.max(
@@ -160,6 +204,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
       strokeType,
       decorations,
       label,
+      scaleLevel,
       handles: { start, end },
     } = this.props
     const midPoint = Vec.med(start.point, end.point)
@@ -172,6 +217,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
             strokeWidth,
             strokeType,
           }}
+          scaleLevel={scaleLevel}
           start={start.point}
           end={end.point}
           decorationStart={decorations?.start}

+ 30 - 2
tldraw/apps/tldraw-logseq/src/lib/shapes/PolygonShape.tsx

@@ -11,15 +11,28 @@ import * as React from 'react'
 import { observer } from 'mobx-react-lite'
 import { CustomStyleProps, withClampedStyles } from './style-props'
 import { TextLabel } from './text/TextLabel'
+import type { SizeLevel } from '.'
+import { action, computed } from 'mobx'
 
 interface PolygonShapeProps extends TLPolygonShapeProps, CustomStyleProps {
   type: 'polygon'
   label: string
+  fontSize: number
   fontWeight: number
   italic: boolean
+  scaleLevel?: SizeLevel
 }
 
-const font = '18px / 1 var(--ls-font-family)'
+const font = '20px / 1 var(--ls-font-family)'
+
+const levelToScale = {
+  xs: 10,
+  sm: 16,
+  md: 20,
+  lg: 32,
+  xl: 48,
+  xxl: 60,
+}
 
 export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
   static id = 'polygon'
@@ -36,6 +49,7 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
     stroke: '',
     fill: '',
     fontWeight: 400,
+    fontSize: 20,
     italic: false,
     noFill: false,
     strokeType: 'line',
@@ -60,6 +74,7 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
           label,
           italic,
           fontWeight,
+          fontSize,
         },
       } = this
 
@@ -69,7 +84,7 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
         label || isEditing
           ? getTextLabelSize(
               label,
-              { fontFamily: 'var(--ls-font-family)', fontSize: 18, lineHeight: 1, fontWeight },
+              { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
               4
             )
           : [0, 0]
@@ -102,6 +117,7 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
           <TextLabel
             font={font}
             text={label}
+            fontSize={fontSize}
             color={getComputedColor(stroke, 'text')}
             offsetX={offset[0]}
             offsetY={offset[1] / scale}
@@ -136,6 +152,18 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
     }
   )
 
+  @computed get scaleLevel() {
+    return this.props.scaleLevel ?? 'md'
+  }
+
+  @action setScaleLevel = async (v?: SizeLevel) => {
+    this.update({
+      scaleLevel: v,
+      fontSize: levelToScale[v ?? 'md'],
+    })
+    this.onResetBounds()
+  }
+
   ReactIndicator = observer(() => {
     const {
       offset: [x, y],

+ 14 - 2
tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/Arrow.tsx

@@ -3,6 +3,7 @@ import Vec from '@tldraw/vec'
 import * as React from 'react'
 import { Arrowhead } from './ArrowHead'
 import { getStraightArrowHeadPoints } from './arrowHelpers'
+import type { SizeLevel } from '../'
 
 interface ShapeStyles {
   stroke: string
@@ -17,6 +18,16 @@ interface ArrowSvgProps {
   end: number[]
   decorationStart: Decoration | undefined
   decorationEnd: Decoration | undefined
+  scaleLevel?: SizeLevel
+}
+
+const levelToScale = {
+  xs: 10,
+  sm: 16,
+  md: 20,
+  lg: 32,
+  xl: 48,
+  xxl: 60,
 }
 
 export const Arrow = React.memo(function StraightArrow({
@@ -25,15 +36,16 @@ export const Arrow = React.memo(function StraightArrow({
   end,
   decorationStart,
   decorationEnd,
+  scaleLevel,
 }: ArrowSvgProps) {
   const arrowDist = Vec.dist(start, end)
   if (arrowDist < 2) return null
   const { strokeWidth } = style
-  const sw = 1 + strokeWidth * 1.618
+  const sw = 1 + strokeWidth * levelToScale[scaleLevel ?? 'md'] / 10
   // Path between start and end points
   const path = 'M' + Vec.toFixed(start) + 'L' + Vec.toFixed(end)
   // Arrowheads
-  const arrowHeadLength = Math.min(arrowDist / 3, strokeWidth * 16)
+  const arrowHeadLength = Math.min(arrowDist / 3, strokeWidth * levelToScale[scaleLevel ?? 'md'])
   const startArrowHead = decorationStart
     ? getStraightArrowHeadPoints(start, end, arrowHeadLength)
     : null

+ 6 - 2
tldraw/apps/tldraw-logseq/src/lib/shapes/text/TextLabel.tsx

@@ -10,6 +10,7 @@ export interface TextLabelProps {
   text: string
   color: string
   fontStyle: string
+  fontSize: number
   fontWeight: number
   onBlur?: () => void
   onChange: (text: string) => void
@@ -25,6 +26,7 @@ export const TextLabel = React.memo(function TextLabel({
   text,
   color,
   fontStyle,
+  fontSize,
   fontWeight,
   offsetX = 0,
   offsetY = 0,
@@ -129,13 +131,13 @@ export const TextLabel = React.memo(function TextLabel({
     if (!elm) return
     const size = getTextLabelSize(
       text,
-      { fontFamily: 'var(--ls-font-family)', fontSize: 18, lineHeight: 1, fontWeight },
+      { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
       4
     )
     elm.style.transform = `scale(${scale}, ${scale}) translate(${offsetX}px, ${offsetY}px)`
     elm.style.width = size[0] + 1 + 'px'
     elm.style.height = size[1] + 1 + 'px'
-  }, [text, fontWeight, offsetY, offsetX, scale])
+  }, [text, fontWeight, fontSize, offsetY, offsetX, scale])
 
   return (
     <div className="tl-text-label-wrapper">
@@ -145,6 +147,7 @@ export const TextLabel = React.memo(function TextLabel({
         style={{
           font,
           fontStyle,
+          fontSize,
           fontWeight,
           color,
           pointerEvents: pointerEvents ? 'all' : 'none',
@@ -158,6 +161,7 @@ export const TextLabel = React.memo(function TextLabel({
               font,
               color,
               fontStyle,
+              fontSize,
               fontWeight,
             }}
             className="tl-text-label-textarea"