From c3649962298db1600947413527db8b5f05ebc7ab Mon Sep 17 00:00:00 2001 From: Triston Armstrong Date: Sun, 6 Oct 2024 12:42:36 -0400 Subject: [PATCH] (feat): make text appear on screen and minimap --- src/components/InfinateCanvas.tsx | 12 ++- src/components/MiniMap.tsx | 30 ++++++ src/components/TextItem.tsx | 108 +++++++++++++++++++++ src/components/cardSelector/TextButton.tsx | 37 +++++++ src/signals/index.ts | 1 + src/signals/texts.ts | 46 +++++++++ src/types/Card.ts | 2 +- src/utils/localStorage.ts | 4 +- 8 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 src/components/TextItem.tsx create mode 100644 src/signals/texts.ts diff --git a/src/components/InfinateCanvas.tsx b/src/components/InfinateCanvas.tsx index 5a7eb0c..d465552 100644 --- a/src/components/InfinateCanvas.tsx +++ b/src/components/InfinateCanvas.tsx @@ -1,5 +1,5 @@ import { useRef, useEffect } from "kaioken" -import { ImagesSignal, NotesSigal, canvasDimentsion } from "../signals" +import { ImagesSignal, NotesSigal, TextSignal, canvasDimentsion } from "../signals" import { NoteCard } from "./NoteCard" import notes from "../signals/notes" import { MiniMap } from "./MiniMap" @@ -8,6 +8,8 @@ import images from "../signals/images" import { CardSelector } from "./cardSelector/CardSelector" import { Logo } from "./Logo" import { useThemeDetector } from "../utils/useThemeDetector" +import { isTheme } from "../utils/isTheme" +import { TextItem } from "./TextItem" export default function InfiniteCanvas() { const containerRef = useRef(null) @@ -74,6 +76,14 @@ export default function InfiniteCanvas() { ) })} + + {Object.keys(TextSignal.default.texts.value).map((itemKey: string) => { + const item = TextSignal.default.texts.value[itemKey] + return ( + + ) + })} + diff --git a/src/components/MiniMap.tsx b/src/components/MiniMap.tsx index 24e524a..01b48bb 100644 --- a/src/components/MiniMap.tsx +++ b/src/components/MiniMap.tsx @@ -3,6 +3,7 @@ import notes, { NoteCardType } from "../signals/notes" import { canvasDimentsion } from "../signals" import { LayerEnum } from "../utils/enums" import images, { ImageCardType } from "../signals/images" +import texts from "../signals/texts" const _MAP_OFFSET = 20 const _MAP_SCALE_FACTOR = 10 @@ -111,6 +112,35 @@ export function MiniMap() { ) })} + {Object.keys(texts.texts.value).map((textKey: textCardType['id']) => { + const text = texts.texts.value[textKey] + const el = useRef(null) + + function _handleItemClick(_e: MouseEvent) { + window.scrollTo({ + left: text.position.x - ((viewportWidth / 2) - (text.dimensions.w / 2)), + top: text.position.y - ((viewportHeight / 2) - (text.dimensions.h / 2)), + behavior: 'smooth' + }) + } + + return ( +
+ ) + })} +
{ + localStorage.setItem("texts", JSON.stringify(texts.texts.value)) + }, time) + } + + function _handleMouseMove(e: MouseEvent) { + e.preventDefault() + if (!pressed.value) return + + newX.current = e.pageX - offsetX.current + newY.current = e.pageY - offsetY.current + const newPos = { x: newX.current, y: newY.current } + + TextSignal.default.updateTextProperty(itemKey, 'position', newPos) + updateLocalStorage() + } + + function _handleMouseUp(e: MouseEvent) { + e.preventDefault() + pressed.value = false + window.removeEventListener('mousemove', _handleMouseMove) + window.removeEventListener('mouseup', _handleMouseUp) + } + + function _handleMouseDown(e: MouseEvent) { + e.preventDefault() + offsetX.current = e.offsetX + offsetY.current = e.offsetY + pressed.value = true + window.addEventListener('mousemove', _handleMouseMove) + window.addEventListener('mouseup', _handleMouseUp) + } + + function _handleResizeMove(e: MouseEvent) { + const { pageX, pageY } = e + const [newX, newY] = [initialResizeX.current - pageX, initialResizeY.current - pageY] + + const newW = -newX + item.dimensions.w + const newH = -newY + item.dimensions.h + const newDim = { w: newW, h: newH } + + TextSignal.default.updateTextProperty(itemKey, 'dimensions', newDim) + TextSignal.default.texts.notify() + } + + + function _handleResizeMouseDown(e: MouseEvent) { + initialResizeX.current = e.pageX + initialResizeY.current = e.pageY + pressed.value = true + window.addEventListener('mousemove', _handleResizeMove) + window.addEventListener('mouseup', _handleResizeMouseUp) + } + + function _handleResizeMouseUp() { + pressed.value = false + updateLocalStorage() + window.removeEventListener('mousemove', _handleResizeMove) + window.removeEventListener('mouseup', _handleResizeMouseUp) + } + + return ( +
focusedItem.value = itemKey} + className="select-none transition flex flex-col justify-stretch shadow-lg rounded border border-[#3c3c3c] absolute border-dashed" + style={{ + zIndex: `${focusedItem.value == itemKey ? LayerEnum.CARD_ELEVATED : LayerEnum.CARD}`, + width: `${item.dimensions.w}px`, + height: `${item.dimensions.h}px`, + top: `${item.position.y}px`, + left: `${item.position.x}px`, + }} + > + + {item.contents} + + +
+ + ) +} + diff --git a/src/components/cardSelector/TextButton.tsx b/src/components/cardSelector/TextButton.tsx index 0abe079..948d1a4 100644 --- a/src/components/cardSelector/TextButton.tsx +++ b/src/components/cardSelector/TextButton.tsx @@ -1,8 +1,28 @@ import { Tooltip } from "./Tooltip"; +import { TextSignal } from "../../signals"; +import texts from "../../signals/texts"; +import { updateLocalStorage } from "../../utils/localStorage"; import { defaultClassName } from "./utils"; export function TextButton() { + function _handleClick(e: MouseEvent) { + TextSignal.default.addText({ + type: "text", + title: "New Note", + contents: "todo: fill me", + position: { + x: e.pageX - 100, + y: e.pageY + (window.innerHeight / 2) - 100 + }, + dimensions: { + w: 200, + h: 100 + } + }) + updateLocalStorage("text", texts.texts.value) + } + return ( + + + + + ) } diff --git a/src/signals/index.ts b/src/signals/index.ts index 21dfeb8..09d8b5e 100644 --- a/src/signals/index.ts +++ b/src/signals/index.ts @@ -6,3 +6,4 @@ export const canvasDimentsion = signal({ width: 3000, height: 3000 }) export * as NotesSigal from "./notes" export * as ImagesSignal from "./images" +export * as TextSignal from "./texts" diff --git a/src/signals/texts.ts b/src/signals/texts.ts new file mode 100644 index 0000000..5f02e7f --- /dev/null +++ b/src/signals/texts.ts @@ -0,0 +1,46 @@ +import { signal } from "kaioken" +import { Card } from "../types" +import { focusedItem } from "." + +export type TextCardType = Card<"text"> + +const texts = signal>({}) + +function loadLocalStorage() { + texts.value = JSON.parse(localStorage.getItem("texts") ?? "{}") +} + +function addText(data: Omit) { + const newCard = { + ...data, + id: crypto.randomUUID(), + } + texts.value[newCard.id] = newCard + texts.notify() + focusedItem.value = newCard.id +} + +function removeText(id: TextCardType["id"]) { + delete texts.value[id] + texts.notify() +} +function updateTextProperty( + id: TextCardType["id"], + property: K, + data: TextCardType[K] +) { + const newData = { + ...texts.value[id], + [property]: data, + } + texts.value[id] = newData + texts.notify() +} + +export default { + texts, + addText, + removeText, + updateTextProperty, + loadLocalStorage, +} diff --git a/src/types/Card.ts b/src/types/Card.ts index cd5ae2c..e810a38 100644 --- a/src/types/Card.ts +++ b/src/types/Card.ts @@ -1,4 +1,4 @@ -export type CardTypes = "note" | "image" +export type CardTypes = "note" | "image" | "text" export type positionCoords = { x: number; y: number } export type dimensionCoords = { w: number; h: number } diff --git a/src/utils/localStorage.ts b/src/utils/localStorage.ts index 57316bf..fcd9549 100644 --- a/src/utils/localStorage.ts +++ b/src/utils/localStorage.ts @@ -1,5 +1,7 @@ +import { CardTypes } from "../types" + export function updateLocalStorage( - location: "notes" | "images", + location: CardTypes, collection: unknown[] | Record ) { localStorage.setItem(location, JSON.stringify(collection))