Skip to content

Commit

Permalink
Merge from jon-dez/main
Browse files Browse the repository at this point in the history
  • Loading branch information
jon-dez committed Nov 13, 2024
2 parents 1f4f660 + c55cf1e commit 98369d6
Show file tree
Hide file tree
Showing 20 changed files with 829 additions and 130 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Tldraw in Obsidian is now available on the official community plugins list!
## Guides

- [Custom icons and fonts](/~https://github.com/holxsam/tldraw-in-obsidian/issues/58#issue-2571070259)
- [Customizing embeds](/~https://github.com/holxsam/tldraw-in-obsidian/issues/59)

## Development

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "tldraw",
"name": "Tldraw",
"version": "1.12.0",
"version": "1.14.1",
"minAppVersion": "0.15.0",
"description": "Integrates Tldraw into Obsidian, allowing users to draw and edit content on a virtual whiteboard.",
"author": "Sam Alhaqab",
Expand Down
144 changes: 144 additions & 0 deletions src/components/BoundsTool.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* Used some code from https://tldraw.dev/examples/shapes/tools/screenshot-tool
*/
import * as React from "react";
import BoundsSelectorTool, {
BoundsDraggingState,
BOUNDS_BOX,
BOUNDS_SHAPES_BOX,
BOUNDS_USING_ASPECT_RATIO,
BOUNDS_ASPECT_RATIO,
BOUNDS_CURRENT_BOX,
BOUNDS_SELECTOR_INITIALIZED
} from "src/tldraw/tools/bounds-selector-tool";
import { Box, Editor, useEditor, useValue } from "tldraw";

function calculateBoundingBoxInEditor(box: Box, editor: Editor) {
const zoomLevel = editor.getZoomLevel()
const { x, y } = editor.pageToViewport({ x: box.x, y: box.y })
return new Box(x, y, box.w * zoomLevel, box.h * zoomLevel)
}

export default function BoundsTool() {
const editor = useEditor();

const toolInitialized = useValue(BOUNDS_SELECTOR_INITIALIZED, () => (
editor.getStateDescendant<BoundsSelectorTool>(BoundsSelectorTool.id)?.boundsSelectorInitialized.get()
), [editor]);

React.useEffect(
() => {
if (toolInitialized === undefined) {
return;
}
if (!toolInitialized) {
editor.getStateDescendant<BoundsSelectorTool>(BoundsSelectorTool.id)?.init();
}
},
[toolInitialized]
);

const currentBox = useValue(BOUNDS_CURRENT_BOX,
() => {
const selectorTool = editor.getStateDescendant<BoundsSelectorTool>(BoundsSelectorTool.id);
const box = selectorTool?.currentBounds.get()

if (!box) return;

return calculateBoundingBoxInEditor(box, editor);
}, [editor],
);

const boundsBox = useValue(BOUNDS_BOX,
() => {
if (editor.getPath() !== BoundsSelectorTool.draggingStatePath) return null;

const draggingState = editor.getStateDescendant<BoundsDraggingState>(BoundsSelectorTool.draggingStatePath)!;
const box = draggingState.boundsBox.get()

return calculateBoundingBoxInEditor(box, editor);
}, [editor],
);

const shapesBox = useValue(BOUNDS_SHAPES_BOX,
() => {
if (editor.getPath() !== BoundsSelectorTool.draggingStatePath) return null;

const draggingState = editor.getStateDescendant<BoundsDraggingState>(BoundsSelectorTool.draggingStatePath)!;
const box = draggingState.shapesBox.get()

if (!box) return null;

return calculateBoundingBoxInEditor(box, editor);
}, [editor],
);

const boundsUsingAspectRatio = useValue(BOUNDS_USING_ASPECT_RATIO, () => (
editor.getStateDescendant<BoundsDraggingState>(BoundsSelectorTool.draggingStatePath)?.boundsUsingAspectRatio.get() ?? false
), [editor]);

const boundsAspectRatio = useValue(BOUNDS_ASPECT_RATIO, () => (
editor.getStateDescendant<BoundsSelectorTool>(BoundsSelectorTool.id)?.aspectRatio.get()
), [editor]);

return (
<>
{
!currentBox ? <></> : (
<div
className="ptl-embed-bounds-selection"
style={{
pointerEvents: 'none',
transform: `translate(${currentBox.x}px, ${currentBox.y}px)`,
width: currentBox.w,
height: currentBox.h,
}}
data-target-bounds={!boundsBox}
/>
)
}
{
!boundsBox ? <></> : (
<div
className="ptl-embed-bounds-selection"
style={{
transform: `translate(${boundsBox.x}px, ${boundsBox.y}px)`,
width: boundsBox.w,
height: boundsBox.h,
}}
data-shade-bg={!shapesBox}
data-target-bounds={!shapesBox}
>
Hold Ctrl to use the bounds within the shapes.
<br />
Hold Shift to use an aspect ratio.
<br />
Press Alt to cycle through aspect ratios.
{
!boundsAspectRatio || !boundsUsingAspectRatio ? <></> : (
<>
<br />
Aspect ratio: {boundsAspectRatio.w}:{boundsAspectRatio.h}
</>
)
}
</div>
)
}
{
!shapesBox ? <></> : (
<div
className="ptl-embed-bounds-selection"
style={{
transform: `translate(${shapesBox.x}px, ${shapesBox.y}px)`,
width: shapesBox.w,
height: shapesBox.h,
}}
data-shade-bg={true}
data-target-bounds={true}
/>
)
}
</>
);
}
30 changes: 30 additions & 0 deletions src/components/BoundsToolSelectedShapesIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* https://tldraw.dev/examples/editor-api/indicators-logic
*/
import * as React from "react"
import BoundsSelectorTool, { BOUNDS_SELECTED_SHAPES, BoundsDraggingState } from "src/tldraw/tools/bounds-selector-tool"
import { useEditor, useEditorComponents, useValue } from "tldraw"

export default function BoundsToolSelectedShapeIndicator() {
const editor = useEditor()

const boundsSelectedShapes = useValue(BOUNDS_SELECTED_SHAPES,
() => {
if (editor.getPath() !== BoundsSelectorTool.draggingStatePath) return null;

const draggingState = editor.getStateDescendant<BoundsDraggingState>(BoundsSelectorTool.draggingStatePath)!;
return draggingState.selectedShapes.get();
}, [editor],
);

const { ShapeIndicator } = useEditorComponents()
if (!ShapeIndicator || !boundsSelectedShapes || !boundsSelectedShapes.length) return null

return (
<div style={{ position: 'absolute', top: 0, left: 0, zIndex: 9999 }}>
{boundsSelectedShapes.map(({ id }) => (
<ShapeIndicator key={id + '_indicator'} shapeId={id} />
))}
</div>
)
}
15 changes: 15 additions & 0 deletions src/components/EmbedTldrawToolBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as React from "react";
import BoundsSelectorTool from "src/tldraw/tools/bounds-selector-tool";
import { DefaultToolbar, DefaultToolbarContent, TldrawUiMenuItem, useIsToolSelected, useTools } from "tldraw";

export default function EmbedTldrawToolBar() {
const tools = useTools();
const boundsSelectorTool = tools[BoundsSelectorTool.id];
const isBoundsSelectorSelected = useIsToolSelected(boundsSelectorTool);
return (
<DefaultToolbar>
<TldrawUiMenuItem isSelected={isBoundsSelectorSelected} {...boundsSelectorTool} />
<DefaultToolbarContent />
</DefaultToolbar>
)
}
Loading

0 comments on commit 98369d6

Please sign in to comment.