Procházet zdrojové kódy

feat: introduce opacity slider

Konstantinos Kaloutas před 3 roky
rodič
revize
9f0cfc571f

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

@@ -338,8 +338,15 @@ const SwatchAction = observer(() => {
     app.persist()
     app.persist()
   }, [])
   }, [])
 
 
-  const value = shapes[0].props.noFill ? shapes[0].props.stroke : shapes[0].props.fill
-  return <ColorInput title="Color Picker" value={value} setColor={handleSetColor} />
+  const handleSetOpacity = React.useCallback((opacity: number) => {
+    shapes.forEach(s => {
+      s.update({ opacity: opacity })
+    })
+    app.persist()
+  }, [])
+
+  const color = shapes[0].props.noFill ? shapes[0].props.stroke : shapes[0].props.fill
+  return <ColorInput title="Color Picker" color={color} opacity={shapes[0].props.opacity} setOpacity={handleSetOpacity} setColor={handleSetColor} />
 })
 })
 
 
 const StrokeTypeAction = observer(() => {
 const StrokeTypeAction = observer(() => {

+ 24 - 8
tldraw/apps/tldraw-logseq/src/components/inputs/ColorInput.tsx

@@ -1,13 +1,16 @@
 import * as React from 'react'
 import * as React from 'react'
 import * as Popover from '@radix-ui/react-popover';
 import * as Popover from '@radix-ui/react-popover';
+import * as Slider from '@radix-ui/react-slider';
 import { TablerIcon } from '../icons'
 import { TablerIcon } from '../icons'
 import { Color } from '@tldraw/core'
 import { Color } from '@tldraw/core'
 interface ColorInputProps extends React.InputHTMLAttributes<HTMLButtonElement> {
 interface ColorInputProps extends React.InputHTMLAttributes<HTMLButtonElement> {
-  value: string
+  color: string
+  opacity: number
   setColor: (value: string) => void
   setColor: (value: string) => void
+  setOpacity: (value: number) => void
 }
 }
 
 
-export function ColorInput({ value, setColor, ...rest }: ColorInputProps) {
+export function ColorInput({ color, opacity, setColor, setOpacity, ...rest }: ColorInputProps) {
   const ref = React.useRef<HTMLDivElement>(null)
   const ref = React.useRef<HTMLDivElement>(null)
 
 
   function renderColor(color: string) {
   function renderColor(color: string) {
@@ -20,11 +23,13 @@ export function ColorInput({ value, setColor, ...rest }: ColorInputProps) {
 
 
   return (
   return (
     <Popover.Root>
     <Popover.Root>
+
       <Popover.Trigger>
       <Popover.Trigger>
-        <button className={`tl-color-drip mx-1`}>
-          {renderColor(value)}
+        <button className="tl-color-drip mx-1">
+          {renderColor(color)}
         </button>
         </button>
       </Popover.Trigger>
       </Popover.Trigger>
+
       <Popover.Portal>
       <Popover.Portal>
         <Popover.Content
         <Popover.Content
           className="tl-popover-content"
           className="tl-popover-content"
@@ -32,16 +37,27 @@ export function ColorInput({ value, setColor, ...rest }: ColorInputProps) {
           sideOffset={15}
           sideOffset={15}
         >
         >
           <div className={"tl-color-palette"}>
           <div className={"tl-color-palette"}>
-            {Object.values(Color).map(color =>
+            {Object.values(Color).map(value =>
               <button
               <button
-                className={`tl-color-drip m-1${color === value ? " active" : ""}`}
-                onClick={()=>setColor(color)}
+                className={`tl-color-drip m-1${value === color ? " active" : ""}`}
+                onClick={()=>setColor(value)}
               >
               >
-                {renderColor(color)}
+                {renderColor(value)}
               </button>
               </button>
             )}
             )}
           </div>
           </div>
+
+          <div className="m-1">
+            <Slider.Root defaultValue={[opacity]} onValueCommit={(value)=>setOpacity(value[0])} max={1} step={0.1} aria-label="Opacity" className="tl-slider-root">
+              <Slider.Track className="tl-slider-track">
+                <Slider.Range className="tl-slider-range" />
+              </Slider.Track>
+              <Slider.Thumb className="tl-slider-thumb" />
+            </Slider.Root>
+          </div>
+
           <Popover.Arrow className="tl-popover-arrow" />
           <Popover.Arrow className="tl-popover-arrow" />
+
         </Popover.Content>
         </Popover.Content>
       </Popover.Portal>
       </Popover.Portal>
     </Popover.Root>
     </Popover.Root>

+ 59 - 4
tldraw/apps/tldraw-logseq/src/styles.css

@@ -20,7 +20,7 @@
   --ls-wb-stroke-color-pink: var(--color-pink-500, pink);
   --ls-wb-stroke-color-pink: var(--color-pink-500, pink);
   --ls-wb-stroke-color-default: var(--ls-secondary-border-color);
   --ls-wb-stroke-color-default: var(--ls-secondary-border-color);
   --ls-wb-text-color-default: var(--ls-secondary-text-color);
   --ls-wb-text-color-default: var(--ls-secondary-text-color);
-  --ls-wb-background-color-default: var(--ls-secondary-background-color);
+  --ls-wb-background-color-default: var(--ls-tertiary-background-color);
 
 
   backface-visibility: hidden;
   backface-visibility: hidden;
 }
 }
@@ -896,7 +896,7 @@ html[data-theme='dark'] {
 }
 }
 
 
 .tl-popover-content {
 .tl-popover-content {
-  @apply rounded-sm;
+  @apply rounded-sm drop-shadow-md;
 
 
   padding: 4px;
   padding: 4px;
   width: 160px;
   width: 160px;
@@ -917,7 +917,7 @@ html[data-theme='dark'] {
 
 
   width: 30px;
   width: 30px;
   height: 30px;
   height: 30px;
-  padding: 4px;
+  padding: 3px;
   border: 1px solid var(--ls-secondary-border-color);
   border: 1px solid var(--ls-secondary-border-color);
   color: var(--ls-secondary-text-color);
   color: var(--ls-secondary-text-color);
 
 
@@ -925,7 +925,7 @@ html[data-theme='dark'] {
     padding: 0;
     padding: 0;
 
 
     .tl-color-bg {
     .tl-color-bg {
-      border: 4px solid var(--ls-selection-background-color);
+      border: 3px solid var(--ls-selection-background-color);
     }
     }
   }
   }
 }
 }
@@ -933,3 +933,58 @@ html[data-theme='dark'] {
 .tl-color-bg {
 .tl-color-bg {
   @apply w-full h-full rounded-sm;
   @apply w-full h-full rounded-sm;
 }
 }
+
+.tl-slider-root {
+  @apply relative flex items-center w-full;
+
+  user-select: none;
+  touch-action: none;
+  background-color: var(--ls-secondary-background-color);
+
+  &[data-orientation="horizontal"] {
+    height: 20px;
+  }
+
+  &[data-orientation="vertical"] {
+    flex-direction: column;
+    width: 20px;
+    height: 100%;
+  }
+}
+
+.tl-slider-track {
+  @apply relative grow rounded-sm w-full;
+
+  background: linear-gradient(90deg, transparent, var(--ls-tertiary-background-color));
+  border: 1px solid var(--ls-secondary-border-color);
+
+  &[data-orientation="horizontal"] {
+    height: 10px;
+  }
+
+  &[data-orientation="vertical"] {
+    width: 10px;
+  }
+}
+
+.tl-slider-range {
+  @apply absolute h-full rounded-sm;
+
+}
+
+.tl-slider-thumb {
+  @apply block rounded-sm;
+
+  width: 8px;
+  height: 14px;
+  background-color: var(--ls-secondary-background-color);
+  border: 1px solid var(--ls-border-color);
+
+  &:hover {
+    background-color: var(--ls-tertiary-background-color);
+  }
+
+  &:focus {
+    box-shadow: 0 0 0 1px var(--color-selectedStroke);
+  }
+}