Procházet zdrojové kódy

feat (whiteboards): Support custom colors

Konstantinos Kaloutas před 2 roky
rodič
revize
d86dbde640

+ 33 - 1
tldraw/apps/tldraw-logseq/src/components/inputs/ColorInput.tsx

@@ -1,9 +1,10 @@
 import type { Side } from '@radix-ui/react-popper'
 import * as Slider from '@radix-ui/react-slider'
-import { Color } from '@tldraw/core'
+import { Color, isBuiltInColor, debounce } from '@tldraw/core'
 import { TablerIcon } from '../icons'
 import { PopoverButton } from '../PopoverButton'
 import { Tooltip } from '../Tooltip'
+import React from 'react'
 
 interface ColorInputProps extends React.HTMLAttributes<HTMLButtonElement> {
   color?: string
@@ -33,6 +34,18 @@ export function ColorInput({
     )
   }
 
+  const handleChangeDebounced = React.useMemo(() => {
+    let latestValue = ''
+
+    const handler: React.ChangeEventHandler<HTMLInputElement> = e => {
+      setColor(latestValue)
+    }
+
+    return debounce(handler, 100, e => {
+      latestValue = e.target.value
+    })
+  }, [])
+
   return (
     <PopoverButton
       {...rest}
@@ -58,6 +71,25 @@ export function ColorInput({
           ))}
         </div>
 
+        <div className="flex items-center tl-custom-color">
+          <div className={`tl-color-drip m-1 mr-3 ${!isBuiltInColor(color) ? 'active' : ''}`}>
+            <div className="color-input-wrapper tl-color-bg">
+              <input
+                className="color-input cursor-pointer"
+                id="tl-custom-color-input"
+                type="color"
+                value={color}
+                onChange={handleChangeDebounced}
+                style={{ opacity: isBuiltInColor(color) ? 0 : 1 }}
+                {...rest}
+              />
+            </div>
+          </div>
+          <label for="tl-custom-color-input" className="cursor-pointer">
+            Select custom color
+          </label>
+        </div>
+
         {setOpacity && (
           <div className="mx-1 my-2">
             <Slider.Root

+ 4 - 1
tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx

@@ -7,6 +7,7 @@ import {
   TLResetBoundsInfo,
   TLResizeInfo,
   validUUID,
+  isBuiltInColor,
 } from '@tldraw/core'
 import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
 import Vec from '@tldraw/vec'
@@ -315,7 +316,9 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
             textRendering: app.viewport.camera.zoom < 0.5 ? 'optimizeSpeed' : 'auto',
             background:
               fill && fill !== 'var(--ls-secondary-background-color)'
-                ? `var(--ls-highlight-color-${fill})`
+                ? isBuiltInColor(fill)
+                  ? `var(--ls-highlight-color-${fill})`
+                  : fill
                 : 'var(--ls-secondary-background-color)',
             opacity,
           }}

+ 17 - 1
tldraw/apps/tldraw-logseq/src/lib/shapes/style-props.tsx

@@ -1,7 +1,11 @@
+import { darken } from 'polished'
 import type { Shape } from '.'
-
+import { withFillShapes } from '../../components/ContextBar/contextBarActionFactory'
+import { isBuiltInColor } from '@tldraw/core'
 export interface CustomStyleProps {
   noFill: boolean
+  fill: string
+  stroke: string
   strokeWidth: number
   strokeType: 'dashed' | 'line'
   opacity: number
@@ -11,5 +15,17 @@ export function withClampedStyles<P>(self: Shape, props: P & Partial<CustomStyle
   if (props.strokeWidth !== undefined) props.strokeWidth = Math.max(props.strokeWidth, 1)
   if (props.opacity !== undefined) props.opacity = Math.min(1, Math.max(props.opacity, 0))
 
+  let fill = props.fill ?? (self.props as any).fill
+  if (
+    fill !== undefined &&
+    !isBuiltInColor(fill) &&
+    fill !== 'var(--ls-secondary-background-color)' &&
+    !props.noFill &&
+    withFillShapes.includes(self.props.type)
+  ) {
+    const strokeColor = darken(0.3, fill)
+    props.stroke = strokeColor
+  }
+
   return props
 }

+ 15 - 5
tldraw/apps/tldraw-logseq/src/styles.css

@@ -79,6 +79,16 @@ html[data-theme='light'] {
   }
 }
 
+.color-input-wrapper {
+  overflow: hidden;
+  width: 24px;
+  height: 24px;
+
+  .color-input {
+    transform: translate(-50%, -50%) scale(4);
+  }
+}
+
 .tl-container {
   overflow: hidden;
 }
@@ -163,13 +173,17 @@ html[data-theme='light'] {
   pointer-events: all;
   position: relative;
   background-color: var(--ls-secondary-background-color);
-  color: #a4b5b6;
   border-radius: 8px;
   white-space: nowrap;
   gap: 8px;
   align-items: stretch;
   box-shadow: var(--shadow-medium);
   z-index: 1000;
+
+  label {
+    font-family: var(--ls-font-family);
+    font-size: 10px;
+  }
 }
 
 .tl-context-bar {
@@ -192,10 +206,6 @@ html[data-theme='light'] {
     padding: 2px;
   }
 
-  .color-input {
-    transform: translate(-50%, -50%) scale(4);
-  }
-
   .switch-input-root {
     all: unset;
     width: 36px;

+ 5 - 1
tldraw/packages/core/src/utils/ColorUtils.ts

@@ -1,7 +1,11 @@
 import { Color } from '../types'
 
+export function isBuiltInColor(color: string | undefined): boolean {
+  return Object.values(Color).includes(color as Color)
+}
+
 export function getComputedColor(color: string | undefined, type: string): string {
-  if (Object.values(Color).includes(color as Color) || color == null) {
+  if (isBuiltInColor(color) || color == null) {
     return `var(--ls-wb-${type}-color-${color ? color : 'default'})`
   }