mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-05-10 12:10:40 +00:00
Unreadable Canvas code, jk 😂
This commit is contained in:
parent
2ac315c039
commit
becb3064c2
10 changed files with 323 additions and 52 deletions
3
apps/web/app/(canvas)/canvas.css
Normal file
3
apps/web/app/(canvas)/canvas.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.tlui-dialog__overlay {
|
||||
position: fixed;
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { createAssetFromUrl } from "./lib/createAssetUrl";
|
|||
import "tldraw/tldraw.css";
|
||||
import { components } from "./enabledComp";
|
||||
import { twitterCardUtil } from "./twitterCard";
|
||||
import { textCardUtil } from "./textCard";
|
||||
import createEmbedsFromUrl from "./lib/createEmbeds";
|
||||
import { loadRemoteSnapshot } from "./lib/loadSnap";
|
||||
import { SaveStatus } from "./savesnap";
|
||||
|
|
@ -11,6 +12,7 @@ import { getAssetUrls } from "@tldraw/assets/selfHosted";
|
|||
import { memo } from "react";
|
||||
import DragContext from "./lib/context";
|
||||
import DropZone from "./dropComponent";
|
||||
import './canvas.css'
|
||||
|
||||
export const Canvas = memo(() => {
|
||||
const [isDraggingOver, setIsDraggingOver] = useState<boolean>(false);
|
||||
|
|
@ -82,7 +84,7 @@ const TldrawComponent =memo(() => {
|
|||
assetUrls={assetUrls}
|
||||
components={components}
|
||||
store={storeWithStatus}
|
||||
shapeUtils={[twitterCardUtil]}
|
||||
shapeUtils={[twitterCardUtil, textCardUtil]}
|
||||
onMount={handleMount}
|
||||
>
|
||||
<div className="absolute left-1/2 top-0 z-[1000000] flex -translate-x-1/2 gap-2 bg-[#2C3439] text-[#B3BCC5]">
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@ import { SettingsIcon, DragIcon } from "@repo/ui/icons";
|
|||
import DraggableComponentsContainer from "@repo/ui/components/canvas/draggableComponent";
|
||||
import { AutocompleteIcon, blockIcon } from "@repo/ui/icons";
|
||||
import Image from "next/image";
|
||||
import { Switch } from "@repo/ui/shadcn/switch";
|
||||
import { Label } from "@repo/ui/shadcn/label";
|
||||
|
||||
function page() {
|
||||
const [value, setValue] = useState("");
|
||||
const [fullScreen, setFullScreen] = useState(false);
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
|
|
@ -42,34 +43,23 @@ function page() {
|
|||
Change Filters
|
||||
<Image src={SettingsIcon} alt="setting-icon" />
|
||||
</div>
|
||||
<div className="px-3 py-5">
|
||||
<input
|
||||
placeholder="search..."
|
||||
onChange={(e) => {
|
||||
setValue(e.target.value);
|
||||
}}
|
||||
value={value}
|
||||
// rows={1}
|
||||
className="w-full resize-none rounded-xl bg-[#151515] px-3 py-4 text-xl text-[#989EA4] outline-none focus:outline-none sm:max-h-52"
|
||||
/>
|
||||
</div>
|
||||
{visible ? (
|
||||
<SidePanel />
|
||||
) : (
|
||||
<h1 className="text-center py-10 text-xl">Need more space to show!</h1>
|
||||
<h1 className="text-center py-10 text-xl">
|
||||
Need more space to show!
|
||||
</h1>
|
||||
)}
|
||||
</div>
|
||||
</Panel>
|
||||
<PanelResizeHandle
|
||||
className={`relative flex items-center transition-all justify-center ${!fullScreen && "px-1"}`}
|
||||
>
|
||||
{/* <div className="absolute z-[1000000] top-1/2 -translate-y-1/2"> */}
|
||||
<div
|
||||
className={`rounded-lg bg-[#2F363B] ${!fullScreen && "px-1"} transition-all py-2`}
|
||||
>
|
||||
<Image src={DragIcon} alt="drag-icon" />
|
||||
</div>
|
||||
{/* </div> */}
|
||||
</PanelResizeHandle>
|
||||
<Panel className="relative" defaultSize={70} minSize={60}>
|
||||
<div
|
||||
|
|
@ -84,26 +74,52 @@ function page() {
|
|||
);
|
||||
}
|
||||
|
||||
const content= [
|
||||
{
|
||||
content: "Nvidia currently dominates the GPU hardware market, with a market share over 97%. This has led some to argue...",
|
||||
icon: AutocompleteIcon,
|
||||
iconAlt: "Autocomplete",
|
||||
extraInfo: "Page Url: https://www.cnbc.com/2024/05/23/nvidia-keeps-hitting-records-can-investors-still-buy-the-stock.html?&qsearchterm=nvidia",
|
||||
},
|
||||
{
|
||||
content: "Nvidia currently dominates the GPU hardware market, with a market share over 97%. This has led some to argue...",
|
||||
icon: blockIcon,
|
||||
iconAlt: "Autocomplete",
|
||||
extraInfo: "Page Url: https://www.cnbc.com/2024/05/23/nvidia-keeps-hitting-records-can-investors-still-buy-the-stock.html?&qsearchterm=nvidia",
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
function SidePanel(){
|
||||
function SidePanel() {
|
||||
const [value, setValue] = useState("");
|
||||
const [dragAsText, setDragAsText] = useState(false);
|
||||
return (
|
||||
<DraggableComponentsContainer content={content} />
|
||||
)
|
||||
<>
|
||||
<div className="px-3 py-5">
|
||||
<input
|
||||
placeholder="search..."
|
||||
onChange={(e) => {
|
||||
setValue(e.target.value);
|
||||
}}
|
||||
value={value}
|
||||
// rows={1}
|
||||
className="w-full resize-none rounded-xl bg-[#151515] px-3 py-4 text-xl text-[#989EA4] outline-none focus:outline-none sm:max-h-52"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-end px-3 py-4">
|
||||
<Switch
|
||||
className="bg-[#151515] data-[state=unchecked]:bg-red-400 data-[state=checked]:bg-blue-400"
|
||||
onCheckedChange={(e) => setDragAsText(e)}
|
||||
id="drag-text-mode"
|
||||
/>
|
||||
<Label htmlFor="drag-text-mode">Drag as Text</Label>
|
||||
</div>
|
||||
<DraggableComponentsContainer content={content} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default page;
|
||||
|
||||
const content = [
|
||||
{
|
||||
content:
|
||||
"Regional growth patterns diverge, with strong performance in the United States and several emerging markets, contrasted by weaker prospects in many advanced economies, particularly in Europe (World Economic Forum) (OECD). The rapid adoption of artificial intelligence (AI) is expected to drive productivity growth, especially in advanced economies, potentially mitigating labor shortages and boosting income levels in emerging markets (World Economic Forum) (OECD). However, ongoing geopolitical tensions and economic fragmentation are likely to maintain a level of uncertainty and volatility in the global economy (World Economic Forum.",
|
||||
icon: AutocompleteIcon,
|
||||
iconAlt: "Autocomplete",
|
||||
extraInfo:
|
||||
"Page Url: https://chatgpt.com/c/762cd44e-1752-495b-967a-aa3c23c6024a",
|
||||
},
|
||||
{
|
||||
content:
|
||||
"As of mid-2024, the global economy is experiencing modest growth with significant regional disparities. Global GDP growth is projected to be around 3.1% in 2024, rising slightly to 3.2% in 2025. This performance, although below the pre-pandemic average, reflects resilience despite various economic pressures, including tight monetary conditions and geopolitical tensions (IMF)(OECD) Inflation is moderating faster than expected, with global headline inflation projected to fall to 5.8% in 2024 and 4.4% in 2025, contributing to improving real incomes and positive trade growth (IMF) (OECD)",
|
||||
icon: blockIcon,
|
||||
iconAlt: "Autocomplete",
|
||||
extraInfo:
|
||||
"Page Url: https://www.cnbc.com/2024/05/23/nvidia-keeps-hitting-records-can-investors-still-buy-the-stock.html?&qsearchterm=nvidia",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -9,6 +9,30 @@ const stripHtmlTags = (html: string): string => {
|
|||
return div.textContent || div.innerText || "";
|
||||
};
|
||||
|
||||
function formatTextToRatio(text: string) {
|
||||
const totalWidth = text.length;
|
||||
const maxLineWidth = Math.floor(totalWidth / 4);
|
||||
|
||||
const words = text.split(" ");
|
||||
let lines = [];
|
||||
let currentLine = "";
|
||||
|
||||
words.forEach((word) => {
|
||||
// Check if adding the next word exceeds the maximum line width
|
||||
if ((currentLine + word).length <= maxLineWidth) {
|
||||
currentLine += (currentLine ? " " : "") + word;
|
||||
} else {
|
||||
// If the current line is full, push it to new line
|
||||
lines.push(currentLine);
|
||||
currentLine = word;
|
||||
}
|
||||
});
|
||||
if (currentLine) {
|
||||
lines.push(currentLine);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
const useDrag = (): DragContextType => {
|
||||
const context = useContext(DragContext);
|
||||
if (!context) {
|
||||
|
|
@ -28,11 +52,22 @@ function DropZone() {
|
|||
console.log("leaver");
|
||||
};
|
||||
|
||||
useEffect(()=> {
|
||||
setInterval(()=> {
|
||||
editor.selectAll();
|
||||
const shapes = editor.getSelectedShapes();
|
||||
const text = shapes.filter((s) => s.type === "text")
|
||||
console.log("hrhh", text)
|
||||
},5000)
|
||||
}, [])
|
||||
|
||||
const handleDrop = useCallback((event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
setIsDraggingOver(false);
|
||||
const dt = event.dataTransfer;
|
||||
if (!dt) {return}
|
||||
if (!dt) {
|
||||
return;
|
||||
}
|
||||
const items = dt.items;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
|
@ -50,7 +85,8 @@ function DropZone() {
|
|||
} else if (items[i]!.kind === "string") {
|
||||
items[i]!.getAsString((data) => {
|
||||
const cleanText = stripHtmlTags(data);
|
||||
handleExternalDroppedContent({ editor, text: cleanText });
|
||||
const onethree = formatTextToRatio(cleanText);
|
||||
handleExternalDroppedContent({ editor, text: onethree });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -72,9 +108,99 @@ function DropZone() {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`h-full w-full absolute top-0 left-0 z-[100000] pointer-events-none ${isDraggingOver && "bg-[#2C3439] pointer-events-auto"}`}
|
||||
className={`h-full flex justify-center items-center w-full absolute top-0 left-0 z-[100000] pointer-events-none ${isDraggingOver && "bg-[#2c3439ad] pointer-events-auto"}`}
|
||||
ref={dropRef}
|
||||
></div>
|
||||
>
|
||||
{
|
||||
isDraggingOver&& (
|
||||
<>
|
||||
<div className="absolute top-4 left-8"><TopRight /></div>
|
||||
<div className="absolute top-4 right-8"><TopLeft /></div>
|
||||
<div className="absolute bottom-4 left-8"><BottomLeft /></div>
|
||||
<div className="absolute bottom-4 right-8"><BottomRight /></div>
|
||||
<h2 className="text-2xl">Drop here to add Content on Canvas</h2>
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TopRight() {
|
||||
return (
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M44 4H12C7.58172 4 4 7.58172 4 12V44"
|
||||
stroke="white"
|
||||
stroke-width="8"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function TopLeft() {
|
||||
return (
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4 4H36C40.4183 4 44 7.58172 44 12V44"
|
||||
stroke="white"
|
||||
stroke-width="8"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function BottomLeft() {
|
||||
return (
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M44 44H12C7.58172 44 4 40.4183 4 36V4"
|
||||
stroke="white"
|
||||
stroke-width="8"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function BottomRight() {
|
||||
return (
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4 44H36C40.4183 44 44 40.4183 44 36V4"
|
||||
stroke="white"
|
||||
stroke-width="8"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,27 @@ function isURL(str: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function formatTextToRatio(text: string) {
|
||||
const totalWidth = text.length;
|
||||
const maxLineWidth = Math.floor(totalWidth / 10);
|
||||
|
||||
const words = text.split(" ");
|
||||
let lines = [];
|
||||
let currentLine = "";
|
||||
|
||||
words.forEach((word) => {
|
||||
if ((currentLine + word).length <= maxLineWidth) {
|
||||
currentLine += (currentLine ? " " : "") + word;
|
||||
} else {
|
||||
lines.push(currentLine);
|
||||
currentLine = word;
|
||||
}
|
||||
});
|
||||
if (currentLine) {
|
||||
lines.push(currentLine);
|
||||
}
|
||||
return {height: (lines.length+1)*18, width: maxLineWidth*10};
|
||||
}
|
||||
|
||||
export function handleExternalDroppedContent({text, editor}: {text:string, editor: Editor}){
|
||||
const position = editor.inputs.shiftKey
|
||||
|
|
@ -105,17 +126,23 @@ export function handleExternalDroppedContent({text, editor}: {text:string, edito
|
|||
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",
|
||||
// },
|
||||
// });
|
||||
const {height, width} =formatTextToRatio(text)
|
||||
editor.createShape({
|
||||
type: "text",
|
||||
x: position.x - 75,
|
||||
y: position.y - 75,
|
||||
props: {
|
||||
text: text,
|
||||
size: "s",
|
||||
textAlign: "start",
|
||||
},
|
||||
type: "Textcard",
|
||||
x: position.x - (width/2),
|
||||
y: position.y - (height/2),
|
||||
props: { content:text, extrainfo: "https://chatgpt.com/c/762cd44e-1752-495b-967a-aa3c23c6024a", w: width, h:height },
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { createTLStore, defaultShapeUtils } from "tldraw";
|
||||
import { createTLStore, defaultShapeUtils, loadSnapshot } from "tldraw";
|
||||
import { twitterCardUtil } from "../twitterCard";
|
||||
import {textCardUtil} from "../textCard"
|
||||
export async function loadRemoteSnapshot() {
|
||||
const res = await fetch(
|
||||
"https://learning-cf.pruthvirajthinks.workers.dev/get/page3",
|
||||
);
|
||||
const snapshot = JSON.parse(await res.json());
|
||||
const newStore = createTLStore({
|
||||
shapeUtils: [...defaultShapeUtils, twitterCardUtil],
|
||||
shapeUtils: [...defaultShapeUtils, twitterCardUtil, textCardUtil],
|
||||
});
|
||||
newStore.loadSnapshot(snapshot);
|
||||
loadSnapshot(newStore, snapshot)
|
||||
return newStore;
|
||||
}
|
||||
66
apps/web/app/(canvas)/textCard.tsx
Normal file
66
apps/web/app/(canvas)/textCard.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import { BaseBoxShapeUtil, HTMLContainer, TLBaseBoxShape, TLBaseShape, useIsEditing, useValue } from "tldraw";
|
||||
|
||||
type ITextCardShape = TLBaseShape<
|
||||
"Textcard",
|
||||
{ w: number; h: number; content: string; extrainfo: string }
|
||||
>;
|
||||
|
||||
export class textCardUtil extends BaseBoxShapeUtil<ITextCardShape> {
|
||||
static override type = "Textcard" as const;
|
||||
|
||||
getDefaultProps(): ITextCardShape["props"] {
|
||||
return {
|
||||
w: 100,
|
||||
h: 50,
|
||||
content: "",
|
||||
extrainfo: "",
|
||||
};
|
||||
}
|
||||
|
||||
component(s: ITextCardShape) {
|
||||
|
||||
const isEditing = useIsEditing(s.id)
|
||||
const isHoveringWhileEditingSameShape = useValue(
|
||||
'is hovering',
|
||||
() => {
|
||||
const { editingShapeId, hoveredShapeId } = this.editor.getCurrentPageState()
|
||||
|
||||
if (editingShapeId && hoveredShapeId !== editingShapeId) {
|
||||
const editingShape = this.editor.getShape(editingShapeId)
|
||||
if (editingShape && this.editor.isShapeOfType<TLBaseBoxShape>(editingShape, 'embed')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const isInteractive = isEditing || isHoveringWhileEditingSameShape
|
||||
return (
|
||||
<HTMLContainer className="flex h-full w-full items-center justify-center">
|
||||
<div
|
||||
style={{
|
||||
height: s.props.h,
|
||||
width: s.props.w,
|
||||
pointerEvents: isInteractive ? "all" : "none",
|
||||
zIndex: isInteractive ? "" : "-1",
|
||||
background: "#2C3439",
|
||||
borderRadius: "16px",
|
||||
padding: "8px 14px"
|
||||
}}
|
||||
>
|
||||
<h1 style={{ fontSize: "15px" }}>{s.props.content}</h1>
|
||||
<p style={{ fontSize: "14px", color: "#369DFD" }}>
|
||||
{s.props.extrainfo}
|
||||
</p>
|
||||
</div>
|
||||
</HTMLContainer>
|
||||
);
|
||||
}
|
||||
|
||||
indicator(shape: ITextCardShape) {
|
||||
return <rect width={shape.props.w} height={shape.props.h} />;
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,7 @@
|
|||
"@radix-ui/react-select": "^2.0.0",
|
||||
"@radix-ui/react-separator": "^1.0.3",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-switch": "^1.1.0",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-toast": "^1.1.5",
|
||||
"@tldraw/assets": "^2.2.0",
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ function DraggableComponents({
|
|||
onDragEnd={handleDragEnd}
|
||||
onDragStart={handleDragStart}
|
||||
draggable
|
||||
className={`flex gap-4 px-3 text-[#989EA4] border-2 transition ${isDragging ? "border-blue-600": "border-[#1F2428]"}`}
|
||||
className={`flex gap-4 px-1 rounded-md text-[#989EA4] border-2 transition ${isDragging ? "border-blue-600": "border-[#1F2428]"}`}
|
||||
>
|
||||
<Image className="select-none" src={icon} alt={iconAlt} />
|
||||
<div className="flex flex-col gap-2">
|
||||
|
|
|
|||
29
packages/ui/shadcn/switch.tsx
Normal file
29
packages/ui/shadcn/switch.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@repo/ui/lib/utils";
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export { Switch }
|
||||
Loading…
Add table
Add a link
Reference in a new issue