aboutsummaryrefslogtreecommitdiff
path: root/apps/web/app
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/app')
-rw-r--r--apps/web/app/(canvas)/canvas.tsx79
-rw-r--r--apps/web/app/(canvas)/dropComponent.tsx76
-rw-r--r--apps/web/app/(canvas)/enabledComp.tsx2
-rw-r--r--apps/web/app/(canvas)/lib/context.tsx11
-rw-r--r--apps/web/app/(canvas)/lib/createEmbeds.ts36
5 files changed, 185 insertions, 19 deletions
diff --git a/apps/web/app/(canvas)/canvas.tsx b/apps/web/app/(canvas)/canvas.tsx
index 9ec57d6d..498ab1eb 100644
--- a/apps/web/app/(canvas)/canvas.tsx
+++ b/apps/web/app/(canvas)/canvas.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Editor, Tldraw, setUserPreferences, TLStoreWithStatus } from "tldraw";
import { createAssetFromUrl } from "./lib/createAssetUrl";
import "tldraw/tldraw.css";
@@ -7,10 +7,53 @@ import { twitterCardUtil } from "./twitterCard";
import createEmbedsFromUrl from "./lib/createEmbeds";
import { loadRemoteSnapshot } from "./lib/loadSnap";
import { SaveStatus } from "./savesnap";
-import { getAssetUrls } from '@tldraw/assets/selfHosted'
-import { memo } from 'react';
+import { getAssetUrls } from "@tldraw/assets/selfHosted";
+import { memo } from "react";
+import DragContext from "./lib/context";
+import DropZone from "./dropComponent";
-export const Canvas = memo(()=>{
+export const Canvas = memo(() => {
+ const [isDraggingOver, setIsDraggingOver] = useState<boolean>(false);
+ const Dragref = useRef<HTMLDivElement | null>(null)
+
+ const handleDragOver = (event: any) => {
+ event.preventDefault();
+ setIsDraggingOver(true);
+ console.log("entere")
+ };
+
+ const handleDragLeave = () => {
+ setIsDraggingOver(false);
+ console.log("leaver")
+ };
+
+ useEffect(() => {
+ const divElement = Dragref.current;
+ if (divElement) {
+ divElement.addEventListener('dragover', handleDragOver);
+ divElement.addEventListener('dragleave', handleDragLeave);
+ }
+ return () => {
+ if (divElement) {
+ divElement.removeEventListener('dragover', handleDragOver);
+ divElement.removeEventListener('dragleave', handleDragLeave);
+ }
+ };
+ }, []);
+
+ return (
+ <DragContext.Provider value={{ isDraggingOver, setIsDraggingOver }}>
+ <div
+ ref={Dragref}
+ className="w-full h-full"
+ >
+ <TldrawComponent />
+ </div>
+ </DragContext.Provider>
+ );
+});
+
+const TldrawComponent =memo(() => {
const [storeWithStatus, setStoreWithStatus] = useState<TLStoreWithStatus>({
status: "loading",
});
@@ -38,18 +81,22 @@ export const Canvas = memo(()=>{
setUserPreferences({ id: "supermemory", isDarkMode: true });
- const assetUrls = getAssetUrls()
+ const assetUrls = getAssetUrls();
return (
- <Tldraw
- assetUrls={assetUrls}
- components={components}
- store={storeWithStatus}
- shapeUtils={[twitterCardUtil]}
- onMount={handleMount}
- >
- <div className="absolute left-1/2 top-0 z-[1000000] flex -translate-x-1/2 gap-2 bg-[#2C3439] text-[#B3BCC5]">
- <SaveStatus />
- </div>
- </Tldraw>
+ <div className="w-full h-full">
+ <Tldraw
+ className="relative"
+ assetUrls={assetUrls}
+ components={components}
+ store={storeWithStatus}
+ shapeUtils={[twitterCardUtil]}
+ onMount={handleMount}
+ >
+ <div className="absolute left-1/2 top-0 z-[1000000] flex -translate-x-1/2 gap-2 bg-[#2C3439] text-[#B3BCC5]">
+ <SaveStatus />
+ </div>
+ <DropZone />
+ </Tldraw>
+ </div>
);
})
diff --git a/apps/web/app/(canvas)/dropComponent.tsx b/apps/web/app/(canvas)/dropComponent.tsx
new file mode 100644
index 00000000..03a32358
--- /dev/null
+++ b/apps/web/app/(canvas)/dropComponent.tsx
@@ -0,0 +1,76 @@
+import React, { useRef, useCallback, useEffect, useContext } from "react";
+import { useEditor } from "tldraw";
+import DragContext, { DragContextType } from "./lib/context";
+import { handleExternalDroppedContent } from "./lib/createEmbeds";
+
+const stripHtmlTags = (html: string): string => {
+ const div = document.createElement("div");
+ div.innerHTML = html;
+ return div.textContent || div.innerText || "";
+};
+
+const useDrag = (): DragContextType => {
+ const context = useContext(DragContext);
+ if (!context) {
+ throw new Error('useCounter must be used within a CounterProvider');
+ }
+ return context;
+};
+
+
+function DropZone() {
+ const dropRef = useRef<HTMLDivElement | null>(null);
+ const {isDraggingOver, setIsDraggingOver} = useDrag();
+
+ const editor = useEditor();
+
+ const handleDrop = useCallback((event: React.DragEvent<HTMLDivElement>) => {
+ event.preventDefault();
+ setIsDraggingOver(false);
+ const dt = event.dataTransfer;
+ const items = dt.items;
+
+ for (let i = 0; i < items.length; i++) {
+ if (items[i]!.kind === "file" && items[i]!.type.startsWith("image/")) {
+ const file = items[i]!.getAsFile();
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ if (e.target) {
+ // setDroppedImage(e.target.result as string);
+ }
+ };
+ reader.readAsDataURL(file);
+ }
+ } else if (items[i]!.kind === "string") {
+ items[i]!.getAsString((data) => {
+ const cleanText = stripHtmlTags(data);
+ handleExternalDroppedContent({editor,text:cleanText})
+ });
+ }
+ }
+ }, []);
+
+ useEffect(() => {
+ const divElement = dropRef.current;
+ if (divElement) {
+ // @ts-ignore
+ divElement.addEventListener("drop", handleDrop);
+ }
+ return () => {
+ if (divElement) {
+ // @ts-ignore
+ divElement.removeEventListener("drop", handleDrop);
+ }
+ };
+ }, []);
+
+ return (
+ <div
+ className={`h-full w-full absolute top-0 left-0 z-[100000] pointer-events-none ${isDraggingOver && "bg-[#2C3439] pointer-events-auto"}`}
+ ref={dropRef}
+ ></div>
+ );
+}
+
+export default DropZone;
diff --git a/apps/web/app/(canvas)/enabledComp.tsx b/apps/web/app/(canvas)/enabledComp.tsx
index 5dbe6ee7..85811b82 100644
--- a/apps/web/app/(canvas)/enabledComp.tsx
+++ b/apps/web/app/(canvas)/enabledComp.tsx
@@ -7,12 +7,12 @@ export const components: Partial<TLUiComponents> = {
TopPanel: null,
DebugPanel: null,
DebugMenu: null,
+ PageMenu: null,
// Minimap: null,
// ContextMenu: null,
// HelpMenu: null,
// ZoomMenu: null,
// StylePanel: null,
- // PageMenu: null,
// NavigationPanel: null,
// Toolbar: null,
// KeyboardShortcutsDialog: null,
diff --git a/apps/web/app/(canvas)/lib/context.tsx b/apps/web/app/(canvas)/lib/context.tsx
new file mode 100644
index 00000000..36a106cf
--- /dev/null
+++ b/apps/web/app/(canvas)/lib/context.tsx
@@ -0,0 +1,11 @@
+import { createContext } from 'react';
+
+export interface DragContextType {
+ isDraggingOver: boolean;
+ setIsDraggingOver: React.Dispatch<React.SetStateAction<boolean>>;
+}
+
+
+const DragContext = createContext<DragContextType | undefined>(undefined);
+
+export default DragContext; \ No newline at end of file
diff --git a/apps/web/app/(canvas)/lib/createEmbeds.ts b/apps/web/app/(canvas)/lib/createEmbeds.ts
index 53d81533..0db3c71b 100644
--- a/apps/web/app/(canvas)/lib/createEmbeds.ts
+++ b/apps/web/app/(canvas)/lib/createEmbeds.ts
@@ -2,8 +2,8 @@ import { AssetRecordType, Editor, TLAsset, TLAssetId, TLBookmarkShape, TLExterna
export default async function createEmbedsFromUrl({url, point, sources, editor}: {
url: string
- point: VecLike | undefined
- sources: TLExternalContentSource[] | undefined
+ point?: VecLike | undefined
+ sources?: TLExternalContentSource[] | undefined
editor: Editor
}){
@@ -87,6 +87,38 @@ export default async function createEmbedsFromUrl({url, point, sources, editor}:
});
}
+function isURL(str: string) {
+ try {
+ new URL(str);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+
+export function handleExternalDroppedContent({text, editor}: {text:string, editor: Editor}){
+ const position = editor.inputs.shiftKey
+ ? editor.inputs.currentPagePoint
+ : editor.getViewportPageBounds().center;
+
+ if (isURL(text)){
+ createEmbedsFromUrl({editor, url: text})
+ } else{
+ editor.createShape({
+ type: "text",
+ x: position.x - 75,
+ y: position.y - 75,
+ props: {
+ text: text,
+ size: "s",
+ textAlign: "start",
+ },
+ });
+
+ }
+}
+
function centerSelectionAroundPoint(editor: Editor, position: VecLike) {
// Re-position shapes so that the center of the group is at the provided point
const viewportPageBounds = editor.getViewportPageBounds()